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_FACE: s = "pt-on-face"; 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 SYMMETRIC: s = "symmetric"; break;
|
||||
case SYMMETRIC_HORIZ: s = "symmetric-h"; break;
|
||||
|
@ -154,6 +156,25 @@ void Constraint::MenuConstrain(int id) {
|
|||
c.type = EQUAL_LENGTH_LINES;
|
||||
c.entityA = gs.entity[0];
|
||||
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) {
|
||||
c.type = EQUAL_RADIUS;
|
||||
c.entityA = gs.entity[0];
|
||||
|
@ -552,6 +573,22 @@ void Constraint::GenerateReal(IdList<Equation,hEquation> *l) {
|
|||
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: {
|
||||
Entity *a = SS.GetEntity(entityA);
|
||||
Entity *b = SS.GetEntity(entityB);
|
||||
|
|
|
@ -95,6 +95,14 @@ void Constraint::DoProjectedPoint(Vector *r) {
|
|||
*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) {
|
||||
if(!SS.GW.showConstraints) return;
|
||||
Group *g = SS.GetGroup(group);
|
||||
|
@ -172,18 +180,8 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||
DoProjectedPoint(&pt);
|
||||
}
|
||||
|
||||
Vector lAB = (lA.Minus(lB)).WithMagnitude(1);
|
||||
Vector closest;
|
||||
// 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));
|
||||
// Find the closest point on the line
|
||||
Vector closest = pt.ClosestPointOnLine(lA, (lA.Minus(lB)));
|
||||
|
||||
LineDrawOrGetDistance(pt, closest);
|
||||
Vector ref = ((closest.Plus(pt)).ScaledBy(0.5)).Plus(disp.offset);
|
||||
|
@ -192,7 +190,7 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||
if(workplane.v != Entity::FREE_IN_3D.v) {
|
||||
// Draw the projection marker from the closest point on the
|
||||
// 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);
|
||||
|
||||
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);
|
||||
a = SS.GetEntity(e->point[0])->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);
|
||||
Vector n = (gn.Cross(ab)).WithMagnitude(10/SS.GW.scale);
|
||||
|
||||
LineDrawOrGetDistance(m.Minus(n), m.Plus(n));
|
||||
if(workplane.v != Entity::FREE_IN_3D.v) {
|
||||
DoProjectedPoint(&a);
|
||||
DoProjectedPoint(&b);
|
||||
}
|
||||
|
||||
DoEqualLenTicks(a, b, gn);
|
||||
}
|
||||
if(type == LENGTH_RATIO) {
|
||||
Vector ref = ((a.Plus(b)).ScaledBy(0.5)).Plus(disp.offset);
|
||||
|
@ -435,6 +435,54 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||
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;
|
||||
case SYMMETRIC:
|
||||
|
|
1
dsc.h
1
dsc.h
|
@ -56,6 +56,7 @@ public:
|
|||
Vector RotatedAbout(Vector orig, Vector axis, double theta);
|
||||
Vector RotatedAbout(Vector axis, double theta);
|
||||
double DistanceToLine(Vector p0, Vector dp);
|
||||
Vector ClosestPointOnLine(Vector p0, Vector dp);
|
||||
double Magnitude(void);
|
||||
Vector WithMagnitude(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 EQUAL_LENGTH_LINES = 50;
|
||||
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_HORIZ = 61;
|
||||
static const int SYMMETRIC_VERT = 62;
|
||||
|
@ -471,6 +473,7 @@ public:
|
|||
char *Label(void);
|
||||
void DoLabel(Vector ref, Vector *labelPos, Vector gr, Vector gu);
|
||||
void DoProjectedPoint(Vector *p);
|
||||
void DoEqualLenTicks(Vector a, Vector b, Vector gn);
|
||||
|
||||
double GetDistance(Point2d mp);
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
return sqrt(x*x + y*y + z*z);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue