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]solver
parent
c05659753a
commit
328a946cc4
|
@ -55,15 +55,22 @@ void Constraint::MenuConstrain(int id) {
|
|||
Entity *e = SS.GetEntity(gs.entity[0]);
|
||||
c.ptA = e->point[0];
|
||||
c.ptB = e->point[1];
|
||||
} else if(gs.circlesOrArcs == 1 && gs.n == 1) {
|
||||
c.type = DIAMETER;
|
||||
c.entityA = gs.entity[0];
|
||||
} else {
|
||||
Error("Bad selection for distance / diameter constraint.");
|
||||
return;
|
||||
}
|
||||
Vector n = SS.GW.projRight.Cross(SS.GW.projUp);
|
||||
Vector a = SS.GetEntity(c.ptA)->PointGetNum();
|
||||
Vector b = SS.GetEntity(c.ptB)->PointGetNum();
|
||||
if(c.type == PT_PT_DISTANCE) {
|
||||
Vector n = SS.GW.projRight.Cross(SS.GW.projUp);
|
||||
Vector a = SS.GetEntity(c.ptA)->PointGetNum();
|
||||
Vector b = SS.GetEntity(c.ptB)->PointGetNum();
|
||||
c.disp.offset = n.Cross(a.Minus(b)).WithMagnitude(50);
|
||||
} else {
|
||||
c.disp.offset = Vector::MakeFrom(0, 0, 0);
|
||||
}
|
||||
|
||||
c.disp.offset = n.Cross(a.Minus(b)).WithMagnitude(50);
|
||||
c.exprA = Expr::FromString("0")->DeepCopyKeep();
|
||||
c.ModifyToSatisfy();
|
||||
AddConstraint(&c);
|
||||
|
@ -330,6 +337,13 @@ void Constraint::Generate(IdList<Equation,hEquation> *l) {
|
|||
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: {
|
||||
Entity *a = SS.GetEntity(ptA);
|
||||
Entity *b = SS.GetEntity(ptB);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
bool Constraint::HasLabel(void) {
|
||||
switch(type) {
|
||||
case PT_PT_DISTANCE:
|
||||
case DIAMETER:
|
||||
return true;
|
||||
|
||||
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) {
|
||||
if(!SS.GW.showConstraints) return;
|
||||
Group *g = SS.GetGroup(group);
|
||||
|
@ -47,7 +77,6 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||
Vector bp = SS.GetEntity(ptB)->PointGetNum();
|
||||
|
||||
Vector ref = ((ap.Plus(bp)).ScaledBy(0.5)).Plus(disp.offset);
|
||||
if(labelPos) *labelPos = ref;
|
||||
|
||||
Vector ab = ap.Minus(bp);
|
||||
Vector ar = ap.Minus(ref);
|
||||
|
@ -59,17 +88,26 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||
LineDrawOrGetDistance(ap, ap.Plus(out));
|
||||
LineDrawOrGetDistance(bp, bp.Plus(out));
|
||||
|
||||
if(dogd.drawing) {
|
||||
glPushMatrix();
|
||||
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);
|
||||
}
|
||||
DoLabel(ref, labelPos, gr, gu);
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -106,7 +144,7 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||
|
||||
case PT_ON_LINE:
|
||||
case PT_IN_PLANE: {
|
||||
double s = 7;
|
||||
double s = 7/SS.GW.scale;
|
||||
Vector p = SS.GetEntity(ptA)->PointGetNum();
|
||||
Vector r = gr.WithMagnitude(s);
|
||||
Vector d = gu.WithMagnitude(s);
|
||||
|
|
29
entity.cpp
29
entity.cpp
|
@ -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) {
|
||||
return SS.GetEntity(normal);
|
||||
}
|
||||
|
@ -404,6 +426,11 @@ void Entity::DrawOrGetDistance(int order) {
|
|||
break;
|
||||
}
|
||||
|
||||
case DISTANCE:
|
||||
case DISTANCE_XFRMD:
|
||||
// These are used only as data structures, nothing to display.
|
||||
break;
|
||||
|
||||
case WORKPLANE: {
|
||||
if(order >= 0 && order != 0) break;
|
||||
if(!SS.GW.showWorkplanes) break;
|
||||
|
@ -477,7 +504,7 @@ void Entity::DrawOrGetDistance(int order) {
|
|||
if(order >= 0 && order != 1) break;
|
||||
|
||||
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 u = q.RotationU(), v = q.RotationV();
|
||||
|
||||
|
|
1
file.cpp
1
file.cpp
|
@ -77,6 +77,7 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = {
|
|||
{ '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.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.numPoint.x", 'f', &(SS.sv.e.numPoint.x) },
|
||||
{ 'e', "Entity.numPoint.y", 'f', &(SS.sv.e.numPoint.y) },
|
||||
|
|
13
glhelper.cpp
13
glhelper.cpp
|
@ -6,7 +6,7 @@
|
|||
static bool ColorLocked;
|
||||
|
||||
#define FONT_SCALE (0.5)
|
||||
static int StrWidth(char *str) {
|
||||
double glxStrWidth(char *str) {
|
||||
int w = 0;
|
||||
for(; *str; str++) {
|
||||
int c = *str;
|
||||
|
@ -15,14 +15,17 @@ static int StrWidth(char *str) {
|
|||
|
||||
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)
|
||||
{
|
||||
double scale = FONT_SCALE/SS.GW.scale;
|
||||
// The characters have height ~21, as they appear in the table.
|
||||
double fh = (21.0)*scale;
|
||||
double fw = StrWidth(str)*scale;
|
||||
double fh = glxStrHeight();
|
||||
double fw = glxStrWidth(str);
|
||||
glPushMatrix();
|
||||
glTranslated(-fw/2, -fh/2, 0);
|
||||
// Undo the (+5, +5) offset that glxWriteText applies.
|
||||
|
|
|
@ -513,7 +513,8 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
|||
Entity *circle = SS.GetEntity(pending.circle);
|
||||
Vector center = SS.GetEntity(circle->point[0])->PointGetNum();
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -634,6 +635,7 @@ void GraphicsWindow::GroupSelection(void) {
|
|||
switch(e->type) {
|
||||
case Entity::WORKPLANE: (gs.workplanes)++; 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:
|
||||
hr = AddRequest(Request::CIRCLE);
|
||||
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));
|
||||
MAYBE_PLACE(hr.entity(1));
|
||||
|
||||
|
@ -757,7 +759,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
|||
case MNU_WORKPLANE:
|
||||
hr = AddRequest(Request::WORKPLANE);
|
||||
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));
|
||||
MAYBE_PLACE(hr.entity(1));
|
||||
|
||||
|
|
22
sketch.cpp
22
sketch.cpp
|
@ -126,7 +126,7 @@ void Group::CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz,
|
|||
case Entity::CIRCLE:
|
||||
en.point[0] = Remap(ep->point[0], 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;
|
||||
|
||||
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);
|
||||
break;
|
||||
|
||||
case Entity::DISTANCE:
|
||||
en.type = Entity::DISTANCE_XFRMD;
|
||||
en.numDistance = ep->DistanceGetNum();
|
||||
break;
|
||||
|
||||
default:
|
||||
oops();
|
||||
}
|
||||
|
@ -302,6 +307,7 @@ void Request::Generate(IdList<Entity,hEntity> *entity,
|
|||
int params = 0;
|
||||
int et = 0;
|
||||
bool hasNormal = false;
|
||||
bool hasDistance = false;
|
||||
int i;
|
||||
|
||||
Entity e;
|
||||
|
@ -328,6 +334,7 @@ void Request::Generate(IdList<Entity,hEntity> *entity,
|
|||
points = 1;
|
||||
params = 1;
|
||||
hasNormal = true;
|
||||
hasDistance = true;
|
||||
break;
|
||||
|
||||
case Request::CUBIC:
|
||||
|
@ -373,7 +380,7 @@ void Request::Generate(IdList<Entity,hEntity> *entity,
|
|||
Entity n;
|
||||
memset(&n, 0, sizeof(n));
|
||||
n.workplane = workplane;
|
||||
n.h = h.entity(16);
|
||||
n.h = h.entity(32);
|
||||
n.group = group;
|
||||
if(workplane.v == Entity::FREE_IN_3D.v) {
|
||||
n.type = Entity::NORMAL_IN_3D;
|
||||
|
@ -393,6 +400,17 @@ void Request::Generate(IdList<Entity,hEntity> *entity,
|
|||
entity->Add(&n);
|
||||
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
|
||||
// we happen to need.
|
||||
for(i = 0; i < params; i++) {
|
||||
|
|
20
sketch.h
20
sketch.h
|
@ -168,6 +168,9 @@ public:
|
|||
static const int NORMAL_IN_PLANE = 3002;
|
||||
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 LINE_SEGMENT = 11000;
|
||||
static const int CUBIC = 12000;
|
||||
|
@ -177,13 +180,17 @@ public:
|
|||
|
||||
// When it comes time to draw an entity, we look here to get the
|
||||
// defining variables.
|
||||
hParam param[4];
|
||||
hEntity point[4];
|
||||
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;
|
||||
Quaternion numNormal;
|
||||
double numDistance;
|
||||
|
||||
hGroup group;
|
||||
hEntity workplane; // or Entity::FREE_IN_3D
|
||||
|
@ -197,6 +204,11 @@ public:
|
|||
bool HasDirection(void);
|
||||
ExprVector GetDirection(void);
|
||||
|
||||
// For distances
|
||||
double DistanceGetNum(void);
|
||||
Expr *DistanceGetExpr(void);
|
||||
void DistanceForceTo(double v);
|
||||
|
||||
bool IsWorkplane(void);
|
||||
// The plane is points P such that P dot (xn, yn, zn) - d = 0
|
||||
void WorkplaneGetPlaneExprs(ExprVector *n, Expr **d);
|
||||
|
@ -301,9 +313,9 @@ public:
|
|||
static const int EQUAL_LENGTH_LINES = 50;
|
||||
static const int SYMMETRIC = 60;
|
||||
static const int AT_MIDPOINT = 70;
|
||||
|
||||
static const int HORIZONTAL = 80;
|
||||
static const int VERTICAL = 81;
|
||||
static const int DIAMETER = 90;
|
||||
|
||||
int tag;
|
||||
hConstraint h;
|
||||
|
@ -339,6 +351,8 @@ public:
|
|||
} dogd; // state for drawing or getting distance (for hit testing)
|
||||
void LineDrawOrGetDistance(Vector a, Vector b);
|
||||
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);
|
||||
Vector GetLabelPos(void);
|
||||
|
|
|
@ -71,6 +71,8 @@ void glxFillPolygon(SPolygon *p);
|
|||
void glxMarkPolygonNormal(SPolygon *p);
|
||||
void glxWriteText(char *str);
|
||||
void glxWriteTextRefCenter(char *str);
|
||||
double glxStrWidth(char *str);
|
||||
double glxStrHeight(void);
|
||||
void glxTranslatev(Vector u);
|
||||
void glxOntoWorkplane(Vector u, Vector v);
|
||||
void glxLockColorTo(double r, double g, double b);
|
||||
|
|
Loading…
Reference in New Issue