From ab44c24cfc2f83fee9fc882252a35c790e294dcd Mon Sep 17 00:00:00 2001 From: Jonathan Westhues Date: Thu, 5 Jun 2008 23:50:08 -0800 Subject: [PATCH] Major speedups, mostly by playing nicer with OpenGL; batch things up more. Also change from stupid linear search lists to sorted binary search lists, remove a stupid bug where I double-generated entities, and don't do the triple drawing of entities (since offsets on the Z buffer were doing the same job already). [git-p4: depot-paths = "//depot/solvespace/": change = 1776] --- drawconstraint.cpp | 1 + dsc.h | 27 ++++++++++++++---- entity.cpp | 70 +++++++++++++++++++++++++++++++--------------- graphicswin.cpp | 31 ++++++-------------- sketch.cpp | 32 +++++++++++---------- sketch.h | 12 ++++---- system.cpp | 4 ++- util.cpp | 6 +++- wishlist.txt | 2 -- 9 files changed, 110 insertions(+), 75 deletions(-) diff --git a/drawconstraint.cpp b/drawconstraint.cpp index da00092..ac5895e 100644 --- a/drawconstraint.cpp +++ b/drawconstraint.cpp @@ -513,6 +513,7 @@ s: void Constraint::Draw(void) { dogd.drawing = true; + glLineWidth(1); DrawOrGetDistance(NULL); } diff --git a/dsc.h b/dsc.h index 412947b..14b09f8 100644 --- a/dsc.h +++ b/dsc.h @@ -102,10 +102,19 @@ public: if(n >= elemsAllocated) { elemsAllocated = (elemsAllocated + 32)*2; elem = (T *)MemRealloc(elem, elemsAllocated*sizeof(elem[0])); - if(!elem) oops(); } - elem[n] = *t; + int i = 0; + if(n == 0 || elem[n-1].h.v < t->h.v) { + i = n; + } else { + while(i < n && elem[i].h.v < t->h.v) { + i++; + } + } + if(i < n && elem[i].h.v == t->h.v) oops(); + memmove(elem+i+1, elem+i, (n-i)*sizeof(elem[0])); + elem[i] = *t; n++; } @@ -119,10 +128,16 @@ public: } T *FindByIdNoOops(H h) { - int i; - for(i = 0; i < n; i++) { - if(elem[i].h.v == h.v) { - return &(elem[i]); + int first = 0, last = n-1; + while(first <= last) { + int mid = (first + last)/2; + H hm = elem[mid].h; + if(hm.v > h.v) { + last = mid-1; // and first stays the same + } else if(hm.v < h.v) { + first = mid+1; // and last stays the same + } else { + return &(elem[mid]); } } return NULL; diff --git a/entity.cpp b/entity.cpp index f81476b..b381430 100644 --- a/entity.cpp +++ b/entity.cpp @@ -642,16 +642,55 @@ void Entity::LineDrawOrGetDistanceOrEdge(Vector a, Vector b) { } } -void Entity::Draw(int order) { +void Entity::DrawAll(void) { + // This handles points and line segments as a special case, because I + // seem to be able to get a huge speedup that way, by consolidating + // stuff to gl. + int i; + if(SS.GW.showPoints) { + double s = 3.5/SS.GW.scale; + Vector r = SS.GW.projRight.ScaledBy(s); + Vector d = SS.GW.projUp.ScaledBy(s); + glxColor3d(0, 0.8, 0); + glPolygonOffset(-10, -10); + glBegin(GL_QUADS); + for(i = 0; i < SS.entity.n; i++) { + Entity *e = &(SS.entity.elem[i]); + if(!e->IsPoint()) continue; + if(!(SS.GetGroup(e->group)->visible)) continue; + + Vector v = e->PointGetNum(); + glxVertex3v(v.Plus (r).Plus (d)); + glxVertex3v(v.Plus (r).Minus(d)); + glxVertex3v(v.Minus(r).Minus(d)); + glxVertex3v(v.Minus(r).Plus (d)); + } + glEnd(); + glPolygonOffset(0, 0); + } + + glLineWidth(1.5); + for(i = 0; i < SS.entity.n; i++) { + Entity *e = &(SS.entity.elem[i]); + if(e->IsPoint()) + { + continue; // already handled + } + e->Draw(); + } + glLineWidth(1); +} + +void Entity::Draw(void) { dogd.drawing = true; dogd.edges = NULL; - DrawOrGetDistance(order); + DrawOrGetDistance(); } void Entity::GenerateEdges(SEdgeList *el) { dogd.drawing = false; dogd.edges = el; - DrawOrGetDistance(-1); + DrawOrGetDistance(); dogd.edges = NULL; } @@ -661,7 +700,7 @@ double Entity::GetDistance(Point2d mp) { dogd.mp = mp; dogd.dmin = 1e12; - DrawOrGetDistance(-1); + DrawOrGetDistance(); return dogd.dmin; } @@ -671,7 +710,7 @@ Vector Entity::GetReferencePos(void) { dogd.edges = NULL; dogd.refp = SS.GW.offset.ScaledBy(-1); - DrawOrGetDistance(-1); + DrawOrGetDistance(); return dogd.refp; } @@ -697,15 +736,14 @@ bool Entity::IsVisible(void) { return true; } -void Entity::DrawOrGetDistance(int order) { - Group *g = SS.GetGroup(group); +void Entity::DrawOrGetDistance(void) { // If an entity is invisible, then it doesn't get shown, and it doesn't // contribute a distance for the selection, but it still generates edges. if(!dogd.edges) { if(!IsVisible()) return; } - glLineWidth(1.5); + Group *g = SS.GetGroup(group); if(group.v != SS.GW.activeGroup.v) { glxColor3d(0.5, 0.3, 0.0); @@ -722,8 +760,6 @@ void Entity::DrawOrGetDistance(int order) { case POINT_N_ROT_AA: case POINT_IN_3D: case POINT_IN_2D: { - if(order >= 0 && order != 2) break; - Vector v = PointGetNum(); if(dogd.drawing) { @@ -754,8 +790,6 @@ void Entity::DrawOrGetDistance(int order) { case NORMAL_N_ROT_AA: case NORMAL_IN_3D: case NORMAL_IN_2D: { - if(order >= 0 && order != 2) break; - int i; for(i = 0; i < 2; i++) { hRequest hr = h.request(); @@ -799,7 +833,7 @@ void Entity::DrawOrGetDistance(int order) { LineDrawOrGetDistance(tip,tip.Minus(v.RotatedAbout(axis, 0.6))); LineDrawOrGetDistance(tip,tip.Minus(v.RotatedAbout(axis,-0.6))); } - glLineWidth(1); + glLineWidth(1.5); break; } @@ -809,8 +843,6 @@ void Entity::DrawOrGetDistance(int order) { break; case WORKPLANE: { - if(order >= 0 && order != 0) break; - Vector p; p = SS.GetEntity(point[0])->PointGetNum(); @@ -841,6 +873,7 @@ void Entity::DrawOrGetDistance(int order) { LineDrawOrGetDistance(mm, mp); LineDrawOrGetDistance(mp, pp); glDisable(GL_LINE_STIPPLE); + glLineWidth(1.5); char *str = DescriptionString()+5; if(dogd.drawing) { @@ -862,7 +895,6 @@ void Entity::DrawOrGetDistance(int order) { } case LINE_SEGMENT: { - if(order >= 0 && order != 1) break; Vector a = SS.GetEntity(point[0])->PointGetNum(); Vector b = SS.GetEntity(point[1])->PointGetNum(); LineDrawOrGetDistanceOrEdge(a, b); @@ -870,7 +902,6 @@ void Entity::DrawOrGetDistance(int order) { } case CUBIC: { - if(order >= 0 && order != 1) break; Vector p0 = SS.GetEntity(point[0])->PointGetNum(); Vector p1 = SS.GetEntity(point[1])->PointGetNum(); Vector p2 = SS.GetEntity(point[2])->PointGetNum(); @@ -892,7 +923,6 @@ void Entity::DrawOrGetDistance(int order) { #define CIRCLE_SIDES(r) (7 + (int)(sqrt(r*SS.GW.scale))) case ARC_OF_CIRCLE: { - if(order >= 0 && order != 1) break; Vector c = SS.GetEntity(point[0])->PointGetNum(); Vector pa = SS.GetEntity(point[1])->PointGetNum(); Vector pb = SS.GetEntity(point[2])->PointGetNum(); @@ -919,8 +949,6 @@ void Entity::DrawOrGetDistance(int order) { } case CIRCLE: { - if(order >= 0 && order != 1) break; - Quaternion q = SS.GetEntity(normal)->NormalGetNum(); double r = SS.GetEntity(distance)->DistanceGetNum(); Vector center = SS.GetEntity(point[0])->PointGetNum(); @@ -948,8 +976,6 @@ void Entity::DrawOrGetDistance(int order) { default: oops(); } - - glLineWidth(1); } void Entity::AddEq(IdList *l, Expr *expr, int index) { diff --git a/graphicswin.cpp b/graphicswin.cpp index 8077a5a..eaca54b 100644 --- a/graphicswin.cpp +++ b/graphicswin.cpp @@ -708,9 +708,11 @@ void GraphicsWindow::Selection::Clear(void) { void GraphicsWindow::Selection::Draw(void) { Vector refp; if(entity.v) { + glLineWidth(1.5); Entity *e = SS.GetEntity(entity); - e->Draw(-1); + e->Draw(); if(emphasized) refp = e->GetReferencePos(); + glLineWidth(1); } if(constraint.v) { Constraint *c = SS.GetConstraint(constraint); @@ -749,7 +751,7 @@ void GraphicsWindow::HitTestMakeSelection(Point2d mp) { int i; double d, dmin = 1e12; Selection s; - memset(&s, 0, sizeof(s)); + ZERO(&s); // Do the entities for(i = 0; i < SS.entity.n; i++) { @@ -1217,8 +1219,6 @@ Vector GraphicsWindow::VectorFromProjs(double right, double up, double fwd) { } void GraphicsWindow::Paint(int w, int h) { - SDWORD in = GetMilliseconds(); - havePainted = true; width = w; height = h; @@ -1272,25 +1272,14 @@ void GraphicsWindow::Paint(int w, int h) { glxUnlockColor(); - int i, a; + int i; // Draw the groups; this fills the polygons in a drawing group, and // draws the solid mesh. (SS.GetGroup(activeGroup))->Draw(); - dbp("done group: %d ms", GetMilliseconds() - in); - // First, draw the entire scene. We don't necessarily want to draw - // things with normal z-buffering behaviour; e.g. we always want to - // draw a line segment in front of a reference. So we have three draw - // levels, and only the first gets normal depth testing. - for(a = 0; a <= 2; a++) { - // Three levels: 0 least prominent (e.g. a reference workplane), 1 is - // middle (e.g. line segment), 2 is always in front (e.g. point). - if(a >= 1 && showHdnLines) glDisable(GL_DEPTH_TEST); - for(i = 0; i < SS.entity.n; i++) { - SS.entity.elem[i].Draw(a); - } - } - dbp("done entity: %d ms", GetMilliseconds() - in); + // Now draw the entities + if(showHdnLines) glDisable(GL_DEPTH_TEST); + Entity::DrawAll(); glDisable(GL_DEPTH_TEST); // Draw the constraints @@ -1308,9 +1297,5 @@ void GraphicsWindow::Paint(int w, int h) { for(i = 0; i < MAX_SELECTED; i++) { selection[i].Draw(); } - - dbp("till end: %d ms", GetMilliseconds() - in); - dbp("entity.n: %d", SS.entity.n); - dbp("param.n: %d", SS.param.n); } diff --git a/sketch.cpp b/sketch.cpp index e9d0ae6..3a993d0 100644 --- a/sketch.cpp +++ b/sketch.cpp @@ -251,19 +251,19 @@ void Group::Generate(IdList *entity, hEntity he = e->h; e = NULL; // As soon as I call CopyEntity, e may become invalid! That // adds entities, which may cause a realloc. - CopyEntity(SS.GetEntity(he), ai, REMAP_BOTTOM, + CopyEntity(entity, SS.GetEntity(he), ai, REMAP_BOTTOM, h.param(0), h.param(1), h.param(2), NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, true, false); - CopyEntity(SS.GetEntity(he), af, REMAP_TOP, + CopyEntity(entity, SS.GetEntity(he), af, REMAP_TOP, h.param(0), h.param(1), h.param(2), NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, true, false); - MakeExtrusionLines(he); + MakeExtrusionLines(entity, he); } // Remapped versions of that arbitrary point will be used to // provide points on the plane faces. - MakeExtrusionTopBottomFaces(pt); + MakeExtrusionTopBottomFaces(entity, pt); break; } @@ -280,7 +280,7 @@ void Group::Generate(IdList *entity, if(e->group.v != opA.v) continue; e->CalculateNumerical(); - CopyEntity(e, + CopyEntity(entity, e, a*2 - (subtype == ONE_SIDED ? 0 : (n-1)), (a == (n - 1)) ? REMAP_LAST : a, h.param(0), h.param(1), h.param(2), @@ -308,7 +308,7 @@ void Group::Generate(IdList *entity, if(e->group.v != opA.v) continue; e->CalculateNumerical(); - CopyEntity(e, + CopyEntity(entity, e, a*2 - (subtype == ONE_SIDED ? 0 : (n-1)), (a == (n - 1)) ? REMAP_LAST : a, h.param(0), h.param(1), h.param(2), @@ -332,7 +332,7 @@ void Group::Generate(IdList *entity, for(i = 0; i < impEntity.n; i++) { Entity *ie = &(impEntity.elem[i]); - CopyEntity(ie, 0, 0, + CopyEntity(entity, ie, 0, 0, h.param(0), h.param(1), h.param(2), h.param(3), h.param(4), h.param(5), h.param(6), false, false); @@ -407,7 +407,7 @@ hEntity Group::Remap(hEntity in, int copyNumber) { return h.entity(em.h.v); } -void Group::MakeExtrusionLines(hEntity in) { +void Group::MakeExtrusionLines(IdList *el, hEntity in) { Entity *ep = SS.GetEntity(in); Entity en; @@ -419,7 +419,7 @@ void Group::MakeExtrusionLines(hEntity in) { en.group = h; en.h = Remap(ep->h, REMAP_PT_TO_LINE); en.type = Entity::LINE_SEGMENT; - SS.entity.Add(&en); + el->Add(&en); } else if(ep->type == Entity::LINE_SEGMENT) { // A line gets extruded to form a plane face; an endpoint of the // original line is a point in the plane, and the line is in the plane. @@ -436,11 +436,12 @@ void Group::MakeExtrusionLines(hEntity in) { en.group = h; en.h = Remap(ep->h, REMAP_LINE_TO_FACE); en.type = Entity::FACE_XPROD; - SS.entity.Add(&en); + el->Add(&en); } } -void Group::MakeExtrusionTopBottomFaces(hEntity pt) { +void Group::MakeExtrusionTopBottomFaces(IdList *el, hEntity pt) +{ if(pt.v == 0) return; Group *src = SS.GetGroup(opA); Vector n = src->poly.normal; @@ -453,14 +454,15 @@ void Group::MakeExtrusionTopBottomFaces(hEntity pt) { en.numNormal = Quaternion::From(0, n.x, n.y, n.z); en.point[0] = Remap(pt, REMAP_TOP); en.h = Remap(Entity::NO_ENTITY, REMAP_TOP); - SS.entity.Add(&en); + el->Add(&en); en.point[0] = Remap(pt, REMAP_BOTTOM); en.h = Remap(Entity::NO_ENTITY, REMAP_BOTTOM); - SS.entity.Add(&en); + el->Add(&en); } -void Group::CopyEntity(Entity *ep, int timesApplied, int remap, +void Group::CopyEntity(IdList *el, + Entity *ep, int timesApplied, int remap, hParam dx, hParam dy, hParam dz, hParam qw, hParam qvx, hParam qvy, hParam qvz, bool asTrans, bool asAxisAngle) @@ -579,7 +581,7 @@ void Group::CopyEntity(Entity *ep, int timesApplied, int remap, default: oops(); } - SS.entity.Add(&en); + el->Add(&en); } void Group::TagEdgesFromLineSegments(SEdgeList *el) { diff --git a/sketch.h b/sketch.h index 409ca91..593fed5 100644 --- a/sketch.h +++ b/sketch.h @@ -158,10 +158,11 @@ public: static const int REMAP_PT_TO_LINE = 1003; static const int REMAP_LINE_TO_FACE = 1004; hEntity Remap(hEntity in, int copyNumber); - void MakeExtrusionLines(hEntity in); - void MakeExtrusionTopBottomFaces(hEntity pt); + void MakeExtrusionLines(IdList *el, hEntity in); + void MakeExtrusionTopBottomFaces(IdList *el, hEntity pt); void TagEdgesFromLineSegments(SEdgeList *sle); - void CopyEntity(Entity *ep, int timesApplied, int remap, + void CopyEntity(IdList *el, + Entity *ep, int timesApplied, int remap, hParam dx, hParam dy, hParam dz, hParam qw, hParam qvx, hParam qvy, hParam qvz, bool asTrans, bool asAxisAngle); @@ -353,9 +354,10 @@ public: } dogd; // state for drawing or getting distance (for hit testing) void LineDrawOrGetDistance(Vector a, Vector b); void LineDrawOrGetDistanceOrEdge(Vector a, Vector b); - void DrawOrGetDistance(int order); + void DrawOrGetDistance(void); - void Draw(int order); + static void DrawAll(void); + void Draw(void); double GetDistance(Point2d mp); void GenerateEdges(SEdgeList *el); Vector GetReferencePos(void); diff --git a/system.cpp b/system.cpp index ea5b1b5..ca1e6bd 100644 --- a/system.cpp +++ b/system.cpp @@ -278,7 +278,9 @@ bool System::SolveLeastSquares(void) { // changes in some parameters, and smaller in others. for(c = 0; c < mat.n; c++) { if(IsDragged(mat.param[c])) { - mat.scale[c] = 1/5.0; + // It's least squares, so this parameter doesn't need to be all + // that big to get a large effect. + mat.scale[c] = 1/20.0; } else { mat.scale[c] = 1; } diff --git a/util.cpp b/util.cpp index 801b6c2..3e305ac 100644 --- a/util.cpp +++ b/util.cpp @@ -131,7 +131,11 @@ Vector Quaternion::RotationV(void) { } Vector Quaternion::RotationN(void) { - return RotationU().Cross(RotationV()); + Vector v; + v.x = 2*w*vy + 2*vx*vz; + v.y = 2*vy*vz - 2*w*vx; + v.z = w*w - vx*vx - vy*vy + vz*vz; + return v; } Vector Quaternion::Rotate(Vector p) { diff --git a/wishlist.txt b/wishlist.txt index e1a7e8b..ce3ee54 100644 --- a/wishlist.txt +++ b/wishlist.txt @@ -1,6 +1,4 @@ -stupidity where stuff gets double-added to entity list -replace linear search through IdLists with faster (binary search?) point face distance constraint STL check for meshes, and T intersection removal