Add two more exotic constraints: equal point-line distances, and
point-line distance equal to line segment length. These are available in both normal and projected versions, with fancy display for all of these. [git-p4: depot-paths = "//depot/solvespace/": change = 1793]solver
parent
d391c43bff
commit
4c6d350cee
|
@ -16,6 +16,8 @@ char *Constraint::DescriptionString(void) {
|
||||||
case PT_ON_LINE: s = "pt-on-line"; break;
|
case PT_ON_LINE: s = "pt-on-line"; break;
|
||||||
case PT_ON_FACE: s = "pt-on-face"; break;
|
case PT_ON_FACE: s = "pt-on-face"; break;
|
||||||
case EQUAL_LENGTH_LINES:s = "eq-length"; break;
|
case EQUAL_LENGTH_LINES:s = "eq-length"; break;
|
||||||
|
case EQ_LEN_PT_LINE_D: s = "eq-length-and-pt-ln-dist"; break;
|
||||||
|
case EQ_PT_LN_DISTANCES:s = "eq-pt-line-distances"; break;
|
||||||
case LENGTH_RATIO: s = "length-ratio"; break;
|
case LENGTH_RATIO: s = "length-ratio"; break;
|
||||||
case SYMMETRIC: s = "symmetric"; break;
|
case SYMMETRIC: s = "symmetric"; break;
|
||||||
case SYMMETRIC_HORIZ: s = "symmetric-h"; break;
|
case SYMMETRIC_HORIZ: s = "symmetric-h"; break;
|
||||||
|
@ -154,6 +156,25 @@ void Constraint::MenuConstrain(int id) {
|
||||||
c.type = EQUAL_LENGTH_LINES;
|
c.type = EQUAL_LENGTH_LINES;
|
||||||
c.entityA = gs.entity[0];
|
c.entityA = gs.entity[0];
|
||||||
c.entityB = gs.entity[1];
|
c.entityB = gs.entity[1];
|
||||||
|
} else if(gs.lineSegments == 2 && gs.points == 2 && gs.n == 4) {
|
||||||
|
c.type = EQ_PT_LN_DISTANCES;
|
||||||
|
c.entityA = gs.entity[0];
|
||||||
|
c.ptA = gs.point[0];
|
||||||
|
c.entityB = gs.entity[1];
|
||||||
|
c.ptB = gs.point[1];
|
||||||
|
} else if(gs.lineSegments == 1 && gs.points == 2 && gs.n == 3) {
|
||||||
|
// The same line segment for the distances, but different
|
||||||
|
// points.
|
||||||
|
c.type = EQ_PT_LN_DISTANCES;
|
||||||
|
c.entityA = gs.entity[0];
|
||||||
|
c.ptA = gs.point[0];
|
||||||
|
c.entityB = gs.entity[0];
|
||||||
|
c.ptB = gs.point[1];
|
||||||
|
} else if(gs.lineSegments == 2 && gs.points == 1 && gs.n == 3) {
|
||||||
|
c.type = EQ_LEN_PT_LINE_D;
|
||||||
|
c.entityA = gs.entity[0];
|
||||||
|
c.entityB = gs.entity[1];
|
||||||
|
c.ptA = gs.point[0];
|
||||||
} else if(gs.circlesOrArcs == 2 && gs.n == 2) {
|
} else if(gs.circlesOrArcs == 2 && gs.n == 2) {
|
||||||
c.type = EQUAL_RADIUS;
|
c.type = EQUAL_RADIUS;
|
||||||
c.entityA = gs.entity[0];
|
c.entityA = gs.entity[0];
|
||||||
|
@ -552,6 +573,22 @@ void Constraint::GenerateReal(IdList<Equation,hEquation> *l) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// These work on distance squared, since the pt-line distances are
|
||||||
|
// signed, and we want the absolute value.
|
||||||
|
case EQ_LEN_PT_LINE_D: {
|
||||||
|
Entity *forLen = SS.GetEntity(entityA);
|
||||||
|
Expr *d1 = Distance(workplane, forLen->point[0], forLen->point[1]);
|
||||||
|
Expr *d2 = PointLineDistance(workplane, ptA, entityB);
|
||||||
|
AddEq(l, (d1->Square())->Minus(d2->Square()), 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EQ_PT_LN_DISTANCES: {
|
||||||
|
Expr *d1 = PointLineDistance(workplane, ptA, entityA);
|
||||||
|
Expr *d2 = PointLineDistance(workplane, ptB, entityB);
|
||||||
|
AddEq(l, (d1->Square())->Minus(d2->Square()), 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case LENGTH_RATIO: {
|
case LENGTH_RATIO: {
|
||||||
Entity *a = SS.GetEntity(entityA);
|
Entity *a = SS.GetEntity(entityA);
|
||||||
Entity *b = SS.GetEntity(entityB);
|
Entity *b = SS.GetEntity(entityB);
|
||||||
|
|
|
@ -95,6 +95,14 @@ void Constraint::DoProjectedPoint(Vector *r) {
|
||||||
*r = p;
|
*r = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Constraint::DoEqualLenTicks(Vector a, Vector b, Vector gn) {
|
||||||
|
Vector m = (a.ScaledBy(1.0/3)).Plus(b.ScaledBy(2.0/3));
|
||||||
|
Vector ab = a.Minus(b);
|
||||||
|
Vector n = (gn.Cross(ab)).WithMagnitude(10/SS.GW.scale);
|
||||||
|
|
||||||
|
LineDrawOrGetDistance(m.Minus(n), m.Plus(n));
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
@ -172,19 +180,9 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
||||||
DoProjectedPoint(&pt);
|
DoProjectedPoint(&pt);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector lAB = (lA.Minus(lB)).WithMagnitude(1);
|
// Find the closest point on the line
|
||||||
Vector closest;
|
Vector closest = pt.ClosestPointOnLine(lA, (lA.Minus(lB)));
|
||||||
// lA, lB, and pt define a plane; the min distance is in
|
|
||||||
// that plane, so calculate its normal
|
|
||||||
Vector pn = (pt.Minus(lA)).Cross(lAB);
|
|
||||||
// The minimum distance line is in that plane, perpendicular
|
|
||||||
// to the line
|
|
||||||
Vector n = pn.Cross(lAB);
|
|
||||||
|
|
||||||
// Calculate the actual distance
|
|
||||||
double d = (lAB.Cross(lA.Minus(pt))).Magnitude();
|
|
||||||
closest = pt.Plus(n.WithMagnitude(d));
|
|
||||||
|
|
||||||
LineDrawOrGetDistance(pt, closest);
|
LineDrawOrGetDistance(pt, closest);
|
||||||
Vector ref = ((closest.Plus(pt)).ScaledBy(0.5)).Plus(disp.offset);
|
Vector ref = ((closest.Plus(pt)).ScaledBy(0.5)).Plus(disp.offset);
|
||||||
DoLabel(ref, labelPos, gr, gu);
|
DoLabel(ref, labelPos, gr, gu);
|
||||||
|
@ -192,7 +190,7 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
||||||
if(workplane.v != Entity::FREE_IN_3D.v) {
|
if(workplane.v != Entity::FREE_IN_3D.v) {
|
||||||
// Draw the projection marker from the closest point on the
|
// Draw the projection marker from the closest point on the
|
||||||
// projected line to the projected point on the real line.
|
// projected line to the projected point on the real line.
|
||||||
lAB = (lA.Minus(lB));
|
Vector lAB = (lA.Minus(lB));
|
||||||
double t = (lA.Minus(closest)).DivPivoting(lAB);
|
double t = (lA.Minus(closest)).DivPivoting(lAB);
|
||||||
|
|
||||||
Vector lA = SS.GetEntity(line->point[0])->PointGetNum();
|
Vector lA = SS.GetEntity(line->point[0])->PointGetNum();
|
||||||
|
@ -422,11 +420,13 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
||||||
Entity *e = SS.GetEntity(i == 0 ? entityA : entityB);
|
Entity *e = SS.GetEntity(i == 0 ? entityA : entityB);
|
||||||
a = SS.GetEntity(e->point[0])->PointGetNum();
|
a = SS.GetEntity(e->point[0])->PointGetNum();
|
||||||
b = SS.GetEntity(e->point[1])->PointGetNum();
|
b = SS.GetEntity(e->point[1])->PointGetNum();
|
||||||
Vector m = (a.ScaledBy(1.0/3)).Plus(b.ScaledBy(2.0/3));
|
|
||||||
Vector ab = a.Minus(b);
|
if(workplane.v != Entity::FREE_IN_3D.v) {
|
||||||
Vector n = (gn.Cross(ab)).WithMagnitude(10/SS.GW.scale);
|
DoProjectedPoint(&a);
|
||||||
|
DoProjectedPoint(&b);
|
||||||
LineDrawOrGetDistance(m.Minus(n), m.Plus(n));
|
}
|
||||||
|
|
||||||
|
DoEqualLenTicks(a, b, gn);
|
||||||
}
|
}
|
||||||
if(type == LENGTH_RATIO) {
|
if(type == LENGTH_RATIO) {
|
||||||
Vector ref = ((a.Plus(b)).ScaledBy(0.5)).Plus(disp.offset);
|
Vector ref = ((a.Plus(b)).ScaledBy(0.5)).Plus(disp.offset);
|
||||||
|
@ -435,6 +435,54 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case EQ_LEN_PT_LINE_D: {
|
||||||
|
Entity *forLen = SS.GetEntity(entityA);
|
||||||
|
Vector a = SS.GetEntity(forLen->point[0])->PointGetNum(),
|
||||||
|
b = SS.GetEntity(forLen->point[1])->PointGetNum();
|
||||||
|
if(workplane.v != Entity::FREE_IN_3D.v) {
|
||||||
|
DoProjectedPoint(&a);
|
||||||
|
DoProjectedPoint(&b);
|
||||||
|
}
|
||||||
|
DoEqualLenTicks(a, b, gn);
|
||||||
|
|
||||||
|
Entity *ln = SS.GetEntity(entityB);
|
||||||
|
Vector la = SS.GetEntity(ln->point[0])->PointGetNum(),
|
||||||
|
lb = SS.GetEntity(ln->point[1])->PointGetNum();
|
||||||
|
Vector pt = SS.GetEntity(ptA)->PointGetNum();
|
||||||
|
if(workplane.v != Entity::FREE_IN_3D.v) {
|
||||||
|
DoProjectedPoint(&pt);
|
||||||
|
la = la.ProjectInto(workplane);
|
||||||
|
lb = lb.ProjectInto(workplane);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector closest = pt.ClosestPointOnLine(la, lb.Minus(la));
|
||||||
|
LineDrawOrGetDistance(pt, closest);
|
||||||
|
DoEqualLenTicks(pt, closest, gn);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case EQ_PT_LN_DISTANCES: {
|
||||||
|
for(int i = 0; i < 2; i++) {
|
||||||
|
Entity *ln = SS.GetEntity(i == 0 ? entityA : entityB);
|
||||||
|
Vector la = SS.GetEntity(ln->point[0])->PointGetNum(),
|
||||||
|
lb = SS.GetEntity(ln->point[1])->PointGetNum();
|
||||||
|
Entity *pte = SS.GetEntity(i == 0 ? ptA : ptB);
|
||||||
|
Vector pt = pte->PointGetNum();
|
||||||
|
|
||||||
|
if(workplane.v != Entity::FREE_IN_3D.v) {
|
||||||
|
DoProjectedPoint(&pt);
|
||||||
|
la = la.ProjectInto(workplane);
|
||||||
|
lb = lb.ProjectInto(workplane);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector closest = pt.ClosestPointOnLine(la, lb.Minus(la));
|
||||||
|
|
||||||
|
LineDrawOrGetDistance(pt, closest);
|
||||||
|
DoEqualLenTicks(pt, closest, gn);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Vector n;
|
Vector n;
|
||||||
case SYMMETRIC:
|
case SYMMETRIC:
|
||||||
|
|
1
dsc.h
1
dsc.h
|
@ -56,6 +56,7 @@ public:
|
||||||
Vector RotatedAbout(Vector orig, Vector axis, double theta);
|
Vector RotatedAbout(Vector orig, Vector axis, double theta);
|
||||||
Vector RotatedAbout(Vector axis, double theta);
|
Vector RotatedAbout(Vector axis, double theta);
|
||||||
double DistanceToLine(Vector p0, Vector dp);
|
double DistanceToLine(Vector p0, Vector dp);
|
||||||
|
Vector ClosestPointOnLine(Vector p0, Vector dp);
|
||||||
double Magnitude(void);
|
double Magnitude(void);
|
||||||
Vector WithMagnitude(double s);
|
Vector WithMagnitude(double s);
|
||||||
Vector ScaledBy(double s);
|
Vector ScaledBy(double s);
|
||||||
|
|
3
sketch.h
3
sketch.h
|
@ -412,6 +412,8 @@ public:
|
||||||
static const int PT_ON_FACE = 43;
|
static const int PT_ON_FACE = 43;
|
||||||
static const int EQUAL_LENGTH_LINES = 50;
|
static const int EQUAL_LENGTH_LINES = 50;
|
||||||
static const int LENGTH_RATIO = 51;
|
static const int LENGTH_RATIO = 51;
|
||||||
|
static const int EQ_LEN_PT_LINE_D = 52;
|
||||||
|
static const int EQ_PT_LN_DISTANCES = 53;
|
||||||
static const int SYMMETRIC = 60;
|
static const int SYMMETRIC = 60;
|
||||||
static const int SYMMETRIC_HORIZ = 61;
|
static const int SYMMETRIC_HORIZ = 61;
|
||||||
static const int SYMMETRIC_VERT = 62;
|
static const int SYMMETRIC_VERT = 62;
|
||||||
|
@ -471,6 +473,7 @@ public:
|
||||||
char *Label(void);
|
char *Label(void);
|
||||||
void DoLabel(Vector ref, Vector *labelPos, Vector gr, Vector gu);
|
void DoLabel(Vector ref, Vector *labelPos, Vector gr, Vector gu);
|
||||||
void DoProjectedPoint(Vector *p);
|
void DoProjectedPoint(Vector *p);
|
||||||
|
void DoEqualLenTicks(Vector a, Vector b, Vector gn);
|
||||||
|
|
||||||
double GetDistance(Point2d mp);
|
double GetDistance(Point2d mp);
|
||||||
Vector GetLabelPos(void);
|
Vector GetLabelPos(void);
|
||||||
|
|
14
util.cpp
14
util.cpp
|
@ -315,6 +315,20 @@ double Vector::DistanceToLine(Vector p0, Vector dp) {
|
||||||
return ((this->Minus(p0)).Cross(dp)).Magnitude() / m;
|
return ((this->Minus(p0)).Cross(dp)).Magnitude() / m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector Vector::ClosestPointOnLine(Vector p0, Vector dp) {
|
||||||
|
dp = dp.WithMagnitude(1);
|
||||||
|
// this, p0, and (p0+dp) define a plane; the min distance is in
|
||||||
|
// that plane, so calculate its normal
|
||||||
|
Vector pn = (this->Minus(p0)).Cross(dp);
|
||||||
|
// The minimum distance line is in that plane, perpendicular
|
||||||
|
// to the line
|
||||||
|
Vector n = pn.Cross(dp);
|
||||||
|
|
||||||
|
// Calculate the actual distance
|
||||||
|
double d = (dp.Cross(p0.Minus(*this))).Magnitude();
|
||||||
|
return this->Plus(n.WithMagnitude(d));
|
||||||
|
}
|
||||||
|
|
||||||
double Vector::Magnitude(void) {
|
double Vector::Magnitude(void) {
|
||||||
return sqrt(x*x + y*y + z*z);
|
return sqrt(x*x + y*y + z*z);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue