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]
solver
Jonathan Westhues 2008-06-05 23:50:08 -08:00
parent 48612bde3d
commit ab44c24cfc
9 changed files with 110 additions and 75 deletions

View File

@ -513,6 +513,7 @@ s:
void Constraint::Draw(void) {
dogd.drawing = true;
glLineWidth(1);
DrawOrGetDistance(NULL);
}

27
dsc.h
View File

@ -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;

View File

@ -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<Equation,hEquation> *l, Expr *expr, int index) {

View File

@ -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);
}

View File

@ -251,19 +251,19 @@ void Group::Generate(IdList<Entity,hEntity> *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,hEntity> *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,hEntity> *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,hEntity> *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<Entity,hEntity> *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<Entity,hEntity> *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<Entity,hEntity> *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) {

View File

@ -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<Entity,hEntity> *el, hEntity in);
void MakeExtrusionTopBottomFaces(IdList<Entity,hEntity> *el, hEntity pt);
void TagEdgesFromLineSegments(SEdgeList *sle);
void CopyEntity(Entity *ep, int timesApplied, int remap,
void CopyEntity(IdList<Entity,hEntity> *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);

View File

@ -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;
}

View File

@ -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) {

View File

@ -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