solvespace/drawconstraint.cpp
Jonathan Westhues 70bf14530d Add point on line constraints, in 2d and 3d. The 3d equations do
not have much motivation behind them, but they seem to work. And
make sure that we don't solve multiple times without repainting in
between, and tweak the text window a bit more.

[git-p4: depot-paths = "//depot/solvespace/": change = 1696]
2008-04-28 01:40:02 -08:00

219 lines
7.5 KiB
C++

#include "solvespace.h"
bool Constraint::HasLabel(void) {
switch(type) {
case PT_PT_DISTANCE:
return true;
default:
return false;
}
}
void Constraint::LineDrawOrGetDistance(Vector a, Vector b) {
if(dogd.drawing) {
glBegin(GL_LINE_STRIP);
glxVertex3v(a);
glxVertex3v(b);
glEnd();
} else {
Point2d ap = SS.GW.ProjectPoint(a);
Point2d bp = SS.GW.ProjectPoint(b);
double d = dogd.mp.DistanceToLine(ap, bp.Minus(ap), true);
dogd.dmin = min(dogd.dmin, d);
}
}
void Constraint::DrawOrGetDistance(Vector *labelPos) {
if(!SS.GW.showConstraints) return;
Group *g = SS.GetGroup(group);
// If the group is hidden, then the constraints are hidden and not
// able to be selected.
if(!(g->visible)) return;
// Unit vectors that describe our current view of the scene. One pixel
// long, not one actual unit.
Vector gr = SS.GW.projRight.ScaledBy(1/SS.GW.scale);
Vector gu = SS.GW.projUp.ScaledBy(1/SS.GW.scale);
Vector gn = (gr.Cross(gu)).WithMagnitude(1/SS.GW.scale);
glxColor3d(1, 0.2, 1);
switch(type) {
case PT_PT_DISTANCE: {
Vector ap = SS.GetEntity(ptA)->PointGetCoords();
Vector bp = SS.GetEntity(ptB)->PointGetCoords();
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);
// Normal to a plan containing the line and the label origin.
Vector n = ab.Cross(ar);
Vector out = ab.Cross(n).WithMagnitude(1);
out = out.ScaledBy(-out.Dot(ar));
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);
}
break;
}
case POINTS_COINCIDENT: {
if(!dogd.drawing) {
for(int i = 0; i < 2; i++) {
Vector p = SS.GetEntity(i == 0 ? ptA : ptB)->
PointGetCoords();
Point2d pp = SS.GW.ProjectPoint(p);
// The point is selected within a radius of 7, from the
// same center; so if the point is visible, then this
// constraint cannot be selected. But that's okay.
dogd.dmin = min(dogd.dmin, pp.DistanceTo(dogd.mp) - 3);
}
break;
}
for(int a = 0; a < 2; a++) {
Vector r = SS.GW.projRight.ScaledBy((a+1)/SS.GW.scale);
Vector d = SS.GW.projUp.ScaledBy((2-a)/SS.GW.scale);
for(int i = 0; i < 2; i++) {
Vector p = SS.GetEntity(i == 0 ? ptA : ptB)->
PointGetCoords();
glxColor3d(0.4, 0, 0.4);
glBegin(GL_QUADS);
glxVertex3v(p.Plus (r).Plus (d));
glxVertex3v(p.Plus (r).Minus(d));
glxVertex3v(p.Minus(r).Minus(d));
glxVertex3v(p.Minus(r).Plus (d));
glEnd();
}
}
break;
}
case PT_ON_LINE:
case PT_IN_PLANE: {
double s = 7;
Vector p = SS.GetEntity(ptA)->PointGetCoords();
Vector r = gr.WithMagnitude(s);
Vector d = gu.WithMagnitude(s);
LineDrawOrGetDistance(p.Plus (r).Plus (d), p.Plus (r).Minus(d));
LineDrawOrGetDistance(p.Plus (r).Minus(d), p.Minus(r).Minus(d));
LineDrawOrGetDistance(p.Minus(r).Minus(d), p.Minus(r).Plus (d));
LineDrawOrGetDistance(p.Minus(r).Plus (d), p.Plus (r).Plus (d));
break;
}
case EQUAL_LENGTH_LINES: {
for(int i = 0; i < 2; i++) {
Entity *e = SS.GetEntity(i == 0 ? entityA : entityB);
Vector a = SS.GetEntity(e->point[0])->PointGetCoords();
Vector b = SS.GetEntity(e->point[1])->PointGetCoords();
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));
}
break;
}
case HORIZONTAL:
case VERTICAL:
if(entityA.v) {
Entity *e = SS.GetEntity(entityA);
Vector a = SS.GetEntity(e->point[0])->PointGetCoords();
Vector b = SS.GetEntity(e->point[1])->PointGetCoords();
Vector m = (a.ScaledBy(0.5)).Plus(b.ScaledBy(0.5));
if(dogd.drawing) {
glPushMatrix();
glxTranslatev(m);
glxOntoWorkplane(gr, gu);
glxWriteText(type == HORIZONTAL ? "H" : "V");
glPopMatrix();
} else {
Point2d ref = SS.GW.ProjectPoint(m);
dogd.dmin = min(dogd.dmin, ref.DistanceTo(dogd.mp)-10);
}
} else {
Vector a = SS.GetEntity(ptA)->PointGetCoords();
Vector b = SS.GetEntity(ptB)->PointGetCoords();
Entity *w = SS.GetEntity(SS.GetEntity(ptA)->workplane);
Vector cu, cv, cn;
w->WorkplaneGetBasisVectors(&cu, &cv);
cn = w->WorkplaneGetNormalVector();
int i;
for(i = 0; i < 2; i++) {
Vector o = (i == 0) ? a : b;
Vector oo = (i == 0) ? a.Minus(b) : b.Minus(a);
Vector d = (type == HORIZONTAL) ? cu : cv;
if(oo.Dot(d) < 0) d = d.ScaledBy(-1);
Vector dp = cn.Cross(d);
d = d.WithMagnitude(14/SS.GW.scale);
Vector c = o.Minus(d);
LineDrawOrGetDistance(o, c);
d = d.WithMagnitude(3/SS.GW.scale);
dp = dp.WithMagnitude(2/SS.GW.scale);
if(dogd.drawing) {
glBegin(GL_QUADS);
glxVertex3v((c.Plus(d)).Plus(dp));
glxVertex3v((c.Minus(d)).Plus(dp));
glxVertex3v((c.Minus(d)).Minus(dp));
glxVertex3v((c.Plus(d)).Minus(dp));
glEnd();
} else {
Point2d ref = SS.GW.ProjectPoint(c);
dogd.dmin = min(dogd.dmin, ref.DistanceTo(dogd.mp)-6);
}
}
}
break;
default: oops();
}
}
void Constraint::Draw(void) {
dogd.drawing = true;
DrawOrGetDistance(NULL);
}
double Constraint::GetDistance(Point2d mp) {
dogd.drawing = false;
dogd.mp = mp;
dogd.dmin = 1e12;
DrawOrGetDistance(NULL);
return dogd.dmin;
}
Vector Constraint::GetLabelPos(void) {
dogd.drawing = false;
dogd.mp.x = 0; dogd.mp.y = 0;
dogd.dmin = 1e12;
Vector p;
DrawOrGetDistance(&p);
return p;
}