Add a diameter constraint, and add a `distance' entity that I can

remap when I copy circle entities, in order to make the radius
numerical somehow (analogy with the POINT_ and NORMAL_XFRMD) thing.

[git-p4: depot-paths = "//depot/solvespace/": change = 1710]
This commit is contained in:
Jonathan Westhues 2008-05-07 00:19:37 -08:00
parent c05659753a
commit 328a946cc4
10 changed files with 150 additions and 30 deletions

View File

@ -55,15 +55,22 @@ void Constraint::MenuConstrain(int id) {
Entity *e = SS.GetEntity(gs.entity[0]); Entity *e = SS.GetEntity(gs.entity[0]);
c.ptA = e->point[0]; c.ptA = e->point[0];
c.ptB = e->point[1]; c.ptB = e->point[1];
} else if(gs.circlesOrArcs == 1 && gs.n == 1) {
c.type = DIAMETER;
c.entityA = gs.entity[0];
} else { } else {
Error("Bad selection for distance / diameter constraint."); Error("Bad selection for distance / diameter constraint.");
return; return;
} }
if(c.type == PT_PT_DISTANCE) {
Vector n = SS.GW.projRight.Cross(SS.GW.projUp); Vector n = SS.GW.projRight.Cross(SS.GW.projUp);
Vector a = SS.GetEntity(c.ptA)->PointGetNum(); Vector a = SS.GetEntity(c.ptA)->PointGetNum();
Vector b = SS.GetEntity(c.ptB)->PointGetNum(); Vector b = SS.GetEntity(c.ptB)->PointGetNum();
c.disp.offset = n.Cross(a.Minus(b)).WithMagnitude(50); c.disp.offset = n.Cross(a.Minus(b)).WithMagnitude(50);
} else {
c.disp.offset = Vector::MakeFrom(0, 0, 0);
}
c.exprA = Expr::FromString("0")->DeepCopyKeep(); c.exprA = Expr::FromString("0")->DeepCopyKeep();
c.ModifyToSatisfy(); c.ModifyToSatisfy();
AddConstraint(&c); AddConstraint(&c);
@ -330,6 +337,13 @@ void Constraint::Generate(IdList<Equation,hEquation> *l) {
break; break;
} }
case DIAMETER: {
Entity *circle = SS.GetEntity(entityA);
Expr *r = (SS.GetEntity(circle->distance))->DistanceGetExpr();
AddEq(l, (r->Times(Expr::FromConstant(2)))->Minus(exprA), 0);
break;
}
case POINTS_COINCIDENT: { case POINTS_COINCIDENT: {
Entity *a = SS.GetEntity(ptA); Entity *a = SS.GetEntity(ptA);
Entity *b = SS.GetEntity(ptB); Entity *b = SS.GetEntity(ptB);

View File

@ -3,6 +3,7 @@
bool Constraint::HasLabel(void) { bool Constraint::HasLabel(void) {
switch(type) { switch(type) {
case PT_PT_DISTANCE: case PT_PT_DISTANCE:
case DIAMETER:
return true; return true;
default: default:
@ -25,6 +26,35 @@ void Constraint::LineDrawOrGetDistance(Vector a, Vector b) {
} }
} }
double Constraint::EllipticalInterpolation(double rx, double ry, double theta) {
double ex = rx*cos(theta);
double ey = ry*sin(theta);
double v = sqrt(ex*ex + ey*ey);
return v;
}
void Constraint::DoLabel(Vector ref, Vector *labelPos, Vector gr, Vector gu) {
char *s = exprA->Print();
if(labelPos) {
// labelPos is from the top left corner (for the text box used to
// edit things), but ref is from the center.
*labelPos = ref.Minus(gr.WithMagnitude(glxStrWidth(s)/2)).Minus(
gu.WithMagnitude(glxStrHeight()/2));
}
if(dogd.drawing) {
glPushMatrix();
glxTranslatev(ref);
glxOntoWorkplane(gr, gu);
glxWriteTextRefCenter(s);
glPopMatrix();
} else {
Point2d o = SS.GW.ProjectPoint(ref);
dogd.dmin = min(dogd.dmin, o.DistanceTo(dogd.mp) - 10);
}
}
void Constraint::DrawOrGetDistance(Vector *labelPos) { void Constraint::DrawOrGetDistance(Vector *labelPos) {
if(!SS.GW.showConstraints) return; if(!SS.GW.showConstraints) return;
Group *g = SS.GetGroup(group); Group *g = SS.GetGroup(group);
@ -47,7 +77,6 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
Vector bp = SS.GetEntity(ptB)->PointGetNum(); Vector bp = SS.GetEntity(ptB)->PointGetNum();
Vector ref = ((ap.Plus(bp)).ScaledBy(0.5)).Plus(disp.offset); Vector ref = ((ap.Plus(bp)).ScaledBy(0.5)).Plus(disp.offset);
if(labelPos) *labelPos = ref;
Vector ab = ap.Minus(bp); Vector ab = ap.Minus(bp);
Vector ar = ap.Minus(ref); Vector ar = ap.Minus(ref);
@ -59,17 +88,26 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
LineDrawOrGetDistance(ap, ap.Plus(out)); LineDrawOrGetDistance(ap, ap.Plus(out));
LineDrawOrGetDistance(bp, bp.Plus(out)); LineDrawOrGetDistance(bp, bp.Plus(out));
if(dogd.drawing) { DoLabel(ref, labelPos, gr, gu);
glPushMatrix(); break;
glxTranslatev(ref);
glxOntoWorkplane(gr, gu);
glxWriteText(exprA->Print());
glPopMatrix();
} else {
Point2d o = SS.GW.ProjectPoint(ref);
dogd.dmin = min(dogd.dmin, o.DistanceTo(dogd.mp) - 10);
} }
case DIAMETER: {
Entity *circle = SS.GetEntity(entityA);
Vector center = SS.GetEntity(circle->point[0])->PointGetNum();
double r = SS.GetEntity(circle->distance)->DistanceGetNum();
Vector ref = center.Plus(disp.offset);
double theta = atan2(disp.offset.Dot(gu), disp.offset.Dot(gr));
double adj = EllipticalInterpolation(
glxStrWidth(exprA->Print())/2, glxStrHeight()/2, theta);
Vector mark = ref.Minus(center);
mark = mark.WithMagnitude(mark.Magnitude()-r);
LineDrawOrGetDistance(ref.Minus(mark.WithMagnitude(adj)),
ref.Minus(mark));
DoLabel(ref, labelPos, gr, gu);
break; break;
} }
@ -106,7 +144,7 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
case PT_ON_LINE: case PT_ON_LINE:
case PT_IN_PLANE: { case PT_IN_PLANE: {
double s = 7; double s = 7/SS.GW.scale;
Vector p = SS.GetEntity(ptA)->PointGetNum(); Vector p = SS.GetEntity(ptA)->PointGetNum();
Vector r = gr.WithMagnitude(s); Vector r = gr.WithMagnitude(s);
Vector d = gu.WithMagnitude(s); Vector d = gu.WithMagnitude(s);

View File

@ -31,6 +31,28 @@ void Entity::WorkplaneGetPlaneExprs(ExprVector *n, Expr **dn) {
} }
} }
double Entity::DistanceGetNum(void) {
if(type == DISTANCE) {
return SS.GetParam(param[0])->val;
} else if(type == DISTANCE_XFRMD) {
return numDistance;
} else oops();
}
Expr *Entity::DistanceGetExpr(void) {
if(type == DISTANCE) {
return Expr::FromParam(param[0]);
} else if(type == DISTANCE_XFRMD) {
return Expr::FromConstant(numDistance);
} else oops();
}
void Entity::DistanceForceTo(double v) {
if(type == DISTANCE) {
(SS.GetParam(param[0]))->val = v;
} else if(type == DISTANCE_XFRMD) {
// do nothing, it's locked
} else oops();
}
Entity *Entity::Normal(void) { Entity *Entity::Normal(void) {
return SS.GetEntity(normal); return SS.GetEntity(normal);
} }
@ -404,6 +426,11 @@ void Entity::DrawOrGetDistance(int order) {
break; break;
} }
case DISTANCE:
case DISTANCE_XFRMD:
// These are used only as data structures, nothing to display.
break;
case WORKPLANE: { case WORKPLANE: {
if(order >= 0 && order != 0) break; if(order >= 0 && order != 0) break;
if(!SS.GW.showWorkplanes) break; if(!SS.GW.showWorkplanes) break;
@ -477,7 +504,7 @@ void Entity::DrawOrGetDistance(int order) {
if(order >= 0 && order != 1) break; if(order >= 0 && order != 1) break;
Quaternion q = SS.GetEntity(normal)->NormalGetNum(); Quaternion q = SS.GetEntity(normal)->NormalGetNum();
double r = SS.GetParam(param[0])->val; double r = SS.GetEntity(distance)->DistanceGetNum();
Vector center = SS.GetEntity(point[0])->PointGetNum(); Vector center = SS.GetEntity(point[0])->PointGetNum();
Vector u = q.RotationU(), v = q.RotationV(); Vector u = q.RotationU(), v = q.RotationV();

View File

@ -77,6 +77,7 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = {
{ 'e', "Entity.point[2].v", 'x', &(SS.sv.e.point[2].v) }, { 'e', "Entity.point[2].v", 'x', &(SS.sv.e.point[2].v) },
{ 'e', "Entity.point[3].v", 'x', &(SS.sv.e.point[3].v) }, { 'e', "Entity.point[3].v", 'x', &(SS.sv.e.point[3].v) },
{ 'e', "Entity.normal.v", 'x', &(SS.sv.e.normal.v) }, { 'e', "Entity.normal.v", 'x', &(SS.sv.e.normal.v) },
{ 'e', "Entity.distance.v", 'x', &(SS.sv.e.distance.v) },
{ 'e', "Entity.workplane.v", 'x', &(SS.sv.e.workplane.v) }, { 'e', "Entity.workplane.v", 'x', &(SS.sv.e.workplane.v) },
{ 'e', "Entity.numPoint.x", 'f', &(SS.sv.e.numPoint.x) }, { 'e', "Entity.numPoint.x", 'f', &(SS.sv.e.numPoint.x) },
{ 'e', "Entity.numPoint.y", 'f', &(SS.sv.e.numPoint.y) }, { 'e', "Entity.numPoint.y", 'f', &(SS.sv.e.numPoint.y) },

View File

@ -6,7 +6,7 @@
static bool ColorLocked; static bool ColorLocked;
#define FONT_SCALE (0.5) #define FONT_SCALE (0.5)
static int StrWidth(char *str) { double glxStrWidth(char *str) {
int w = 0; int w = 0;
for(; *str; str++) { for(; *str; str++) {
int c = *str; int c = *str;
@ -15,14 +15,17 @@ static int StrWidth(char *str) {
w += Font[c].width; w += Font[c].width;
} }
return w; return w*FONT_SCALE/SS.GW.scale;
}
double glxStrHeight(void) {
// The characters have height ~21, as they appear in the table.
return 21.0*FONT_SCALE/SS.GW.scale;
} }
void glxWriteTextRefCenter(char *str) void glxWriteTextRefCenter(char *str)
{ {
double scale = FONT_SCALE/SS.GW.scale; double scale = FONT_SCALE/SS.GW.scale;
// The characters have height ~21, as they appear in the table. double fh = glxStrHeight();
double fh = (21.0)*scale; double fw = glxStrWidth(str);
double fw = StrWidth(str)*scale;
glPushMatrix(); glPushMatrix();
glTranslated(-fw/2, -fh/2, 0); glTranslated(-fw/2, -fh/2, 0);
// Undo the (+5, +5) offset that glxWriteText applies. // Undo the (+5, +5) offset that glxWriteText applies.

View File

@ -513,7 +513,8 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
Entity *circle = SS.GetEntity(pending.circle); Entity *circle = SS.GetEntity(pending.circle);
Vector center = SS.GetEntity(circle->point[0])->PointGetNum(); Vector center = SS.GetEntity(circle->point[0])->PointGetNum();
Point2d c2 = ProjectPoint(center); Point2d c2 = ProjectPoint(center);
SS.GetParam(circle->param[0])->val = c2.DistanceTo(mp)*scale; double r = c2.DistanceTo(mp)*scale;
SS.GetEntity(circle->distance)->DistanceForceTo(r);
break; break;
} }
@ -634,6 +635,7 @@ void GraphicsWindow::GroupSelection(void) {
switch(e->type) { switch(e->type) {
case Entity::WORKPLANE: (gs.workplanes)++; break; case Entity::WORKPLANE: (gs.workplanes)++; break;
case Entity::LINE_SEGMENT: (gs.lineSegments)++; break; case Entity::LINE_SEGMENT: (gs.lineSegments)++; break;
case Entity::CIRCLE: (gs.circlesOrArcs)++; break;
} }
} }
} }
@ -726,7 +728,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
case MNU_CIRCLE: case MNU_CIRCLE:
hr = AddRequest(Request::CIRCLE); hr = AddRequest(Request::CIRCLE);
SS.GetEntity(hr.entity(1))->PointForceTo(v); SS.GetEntity(hr.entity(1))->PointForceTo(v);
SS.GetEntity(hr.entity(16))->NormalForceTo( SS.GetEntity(hr.entity(32))->NormalForceTo(
Quaternion::MakeFrom(SS.GW.projRight, SS.GW.projUp)); Quaternion::MakeFrom(SS.GW.projRight, SS.GW.projUp));
MAYBE_PLACE(hr.entity(1)); MAYBE_PLACE(hr.entity(1));
@ -757,7 +759,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
case MNU_WORKPLANE: case MNU_WORKPLANE:
hr = AddRequest(Request::WORKPLANE); hr = AddRequest(Request::WORKPLANE);
SS.GetEntity(hr.entity(1))->PointForceTo(v); SS.GetEntity(hr.entity(1))->PointForceTo(v);
SS.GetEntity(hr.entity(16))->NormalForceTo( SS.GetEntity(hr.entity(32))->NormalForceTo(
Quaternion::MakeFrom(SS.GW.projRight, SS.GW.projUp)); Quaternion::MakeFrom(SS.GW.projRight, SS.GW.projUp));
MAYBE_PLACE(hr.entity(1)); MAYBE_PLACE(hr.entity(1));

View File

@ -126,7 +126,7 @@ void Group::CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz,
case Entity::CIRCLE: case Entity::CIRCLE:
en.point[0] = Remap(ep->point[0], a); en.point[0] = Remap(ep->point[0], a);
en.normal = Remap(ep->normal, a); en.normal = Remap(ep->normal, a);
en.param[0] = ep->param[0]; // XXX make numerical somehow later en.distance = Remap(ep->distance, a);
break; break;
case Entity::POINT_IN_3D: case Entity::POINT_IN_3D:
@ -159,6 +159,11 @@ void Group::CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz,
en.point[0] = Remap(ep->point[0], a); en.point[0] = Remap(ep->point[0], a);
break; break;
case Entity::DISTANCE:
en.type = Entity::DISTANCE_XFRMD;
en.numDistance = ep->DistanceGetNum();
break;
default: default:
oops(); oops();
} }
@ -302,6 +307,7 @@ void Request::Generate(IdList<Entity,hEntity> *entity,
int params = 0; int params = 0;
int et = 0; int et = 0;
bool hasNormal = false; bool hasNormal = false;
bool hasDistance = false;
int i; int i;
Entity e; Entity e;
@ -328,6 +334,7 @@ void Request::Generate(IdList<Entity,hEntity> *entity,
points = 1; points = 1;
params = 1; params = 1;
hasNormal = true; hasNormal = true;
hasDistance = true;
break; break;
case Request::CUBIC: case Request::CUBIC:
@ -373,7 +380,7 @@ void Request::Generate(IdList<Entity,hEntity> *entity,
Entity n; Entity n;
memset(&n, 0, sizeof(n)); memset(&n, 0, sizeof(n));
n.workplane = workplane; n.workplane = workplane;
n.h = h.entity(16); n.h = h.entity(32);
n.group = group; n.group = group;
if(workplane.v == Entity::FREE_IN_3D.v) { if(workplane.v == Entity::FREE_IN_3D.v) {
n.type = Entity::NORMAL_IN_3D; n.type = Entity::NORMAL_IN_3D;
@ -393,6 +400,17 @@ void Request::Generate(IdList<Entity,hEntity> *entity,
entity->Add(&n); entity->Add(&n);
e.normal = n.h; e.normal = n.h;
} }
if(hasDistance) {
Entity d;
memset(&d, 0, sizeof(d));
d.workplane = workplane;
d.h = h.entity(64);
d.group = group;
d.type = Entity::DISTANCE;
d.param[0] = AddParam(param, h.param(64));
entity->Add(&d);
e.distance = d.h;
}
// And generate any params not associated with the point that // And generate any params not associated with the point that
// we happen to need. // we happen to need.
for(i = 0; i < params; i++) { for(i = 0; i < params; i++) {

View File

@ -168,6 +168,9 @@ public:
static const int NORMAL_IN_PLANE = 3002; static const int NORMAL_IN_PLANE = 3002;
static const int NORMAL_XFRMD = 3010; static const int NORMAL_XFRMD = 3010;
static const int DISTANCE = 4000;
static const int DISTANCE_XFRMD = 4001;
static const int WORKPLANE = 10000; static const int WORKPLANE = 10000;
static const int LINE_SEGMENT = 11000; static const int LINE_SEGMENT = 11000;
static const int CUBIC = 12000; static const int CUBIC = 12000;
@ -177,13 +180,17 @@ public:
// When it comes time to draw an entity, we look here to get the // When it comes time to draw an entity, we look here to get the
// defining variables. // defining variables.
hParam param[4];
hEntity point[4]; hEntity point[4];
hEntity normal; hEntity normal;
hEntity distance;
// The only types that have their own params are points, normals,
// and directions.
hParam param[4];
// Derived points are a symbolic offset from a constant base. // Transformed points/normals/distances have their numerical value.
Vector numPoint; Vector numPoint;
Quaternion numNormal; Quaternion numNormal;
double numDistance;
hGroup group; hGroup group;
hEntity workplane; // or Entity::FREE_IN_3D hEntity workplane; // or Entity::FREE_IN_3D
@ -197,6 +204,11 @@ public:
bool HasDirection(void); bool HasDirection(void);
ExprVector GetDirection(void); ExprVector GetDirection(void);
// For distances
double DistanceGetNum(void);
Expr *DistanceGetExpr(void);
void DistanceForceTo(double v);
bool IsWorkplane(void); bool IsWorkplane(void);
// The plane is points P such that P dot (xn, yn, zn) - d = 0 // The plane is points P such that P dot (xn, yn, zn) - d = 0
void WorkplaneGetPlaneExprs(ExprVector *n, Expr **d); void WorkplaneGetPlaneExprs(ExprVector *n, Expr **d);
@ -301,9 +313,9 @@ public:
static const int EQUAL_LENGTH_LINES = 50; static const int EQUAL_LENGTH_LINES = 50;
static const int SYMMETRIC = 60; static const int SYMMETRIC = 60;
static const int AT_MIDPOINT = 70; static const int AT_MIDPOINT = 70;
static const int HORIZONTAL = 80; static const int HORIZONTAL = 80;
static const int VERTICAL = 81; static const int VERTICAL = 81;
static const int DIAMETER = 90;
int tag; int tag;
hConstraint h; hConstraint h;
@ -339,6 +351,8 @@ public:
} dogd; // state for drawing or getting distance (for hit testing) } dogd; // state for drawing or getting distance (for hit testing)
void LineDrawOrGetDistance(Vector a, Vector b); void LineDrawOrGetDistance(Vector a, Vector b);
void DrawOrGetDistance(Vector *labelPos); void DrawOrGetDistance(Vector *labelPos);
double EllipticalInterpolation(double rx, double ry, double theta);
void DoLabel(Vector ref, Vector *labelPos, Vector gr, Vector gu);
double GetDistance(Point2d mp); double GetDistance(Point2d mp);
Vector GetLabelPos(void); Vector GetLabelPos(void);

View File

@ -71,6 +71,8 @@ void glxFillPolygon(SPolygon *p);
void glxMarkPolygonNormal(SPolygon *p); void glxMarkPolygonNormal(SPolygon *p);
void glxWriteText(char *str); void glxWriteText(char *str);
void glxWriteTextRefCenter(char *str); void glxWriteTextRefCenter(char *str);
double glxStrWidth(char *str);
double glxStrHeight(void);
void glxTranslatev(Vector u); void glxTranslatev(Vector u);
void glxOntoWorkplane(Vector u, Vector v); void glxOntoWorkplane(Vector u, Vector v);
void glxLockColorTo(double r, double g, double b); void glxLockColorTo(double r, double g, double b);

1
ui.h
View File

@ -222,6 +222,7 @@ public:
int entities; int entities;
int workplanes; int workplanes;
int lineSegments; int lineSegments;
int circlesOrArcs;
int n; int n;
} gs; } gs;
void GroupSelection(void); void GroupSelection(void);