2013-07-28 22:08:34 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Given a constraint, draw a graphical and user-selectable representation
|
|
|
|
// of that constraint on-screen. We can either draw with gl, or compute the
|
|
|
|
// distance from a point (the location of the mouse pointer) to the lines
|
|
|
|
// that we would have drawn, for selection.
|
|
|
|
//
|
|
|
|
// Copyright 2008-2013 Jonathan Westhues.
|
|
|
|
//-----------------------------------------------------------------------------
|
2008-04-14 10:28:32 +00:00
|
|
|
#include "solvespace.h"
|
|
|
|
|
2008-04-21 08:16:38 +00:00
|
|
|
void Constraint::LineDrawOrGetDistance(Vector a, Vector b) {
|
|
|
|
if(dogd.drawing) {
|
2016-02-21 19:07:58 +00:00
|
|
|
hStyle hs = disp.style;
|
|
|
|
if(hs.v == 0) hs.v = Style::CONSTRAINT;
|
2009-09-24 15:52:48 +00:00
|
|
|
|
2009-07-03 20:55:57 +00:00
|
|
|
if(dogd.sel) {
|
2009-09-24 15:52:48 +00:00
|
|
|
dogd.sel->AddEdge(a, b, hs.v);
|
2009-07-03 20:55:57 +00:00
|
|
|
} else {
|
2016-02-21 19:07:58 +00:00
|
|
|
if(Style::Width(hs) >= 3.0) {
|
2013-10-22 04:45:06 +00:00
|
|
|
ssglFatLine(a, b, Style::Width(hs) / SS.GW.scale);
|
2009-09-24 15:52:48 +00:00
|
|
|
} else {
|
|
|
|
glBegin(GL_LINE_STRIP);
|
2013-10-22 04:45:06 +00:00
|
|
|
ssglVertex3v(a);
|
|
|
|
ssglVertex3v(b);
|
2009-09-24 15:52:48 +00:00
|
|
|
glEnd();
|
|
|
|
}
|
2009-07-03 20:55:57 +00:00
|
|
|
}
|
2008-04-21 08:16:38 +00:00
|
|
|
} 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);
|
|
|
|
}
|
2008-05-26 09:56:50 +00:00
|
|
|
dogd.refp = (a.Plus(b)).ScaledBy(0.5);
|
2008-04-21 08:16:38 +00:00
|
|
|
}
|
|
|
|
|
2009-07-03 20:55:57 +00:00
|
|
|
static void LineCallback(void *fndata, Vector a, Vector b)
|
|
|
|
{
|
|
|
|
Constraint *c = (Constraint *)fndata;
|
|
|
|
c->LineDrawOrGetDistance(a, b);
|
|
|
|
}
|
|
|
|
|
2015-11-06 08:40:12 +00:00
|
|
|
std::string Constraint::Label(void) {
|
|
|
|
std::string result;
|
2008-06-11 04:22:52 +00:00
|
|
|
if(type == ANGLE) {
|
2016-04-16 01:13:06 +00:00
|
|
|
if(valA == floor(valA)) {
|
|
|
|
result = ssprintf("%.0f°", valA);
|
|
|
|
} else {
|
|
|
|
result = ssprintf("%.2f°", valA);
|
|
|
|
}
|
2008-06-11 04:22:52 +00:00
|
|
|
} else if(type == LENGTH_RATIO) {
|
2015-11-06 08:40:12 +00:00
|
|
|
result = ssprintf("%.3f:1", valA);
|
2008-06-12 08:58:58 +00:00
|
|
|
} else if(type == COMMENT) {
|
2015-11-06 08:40:12 +00:00
|
|
|
result = comment;
|
2010-05-23 06:21:42 +00:00
|
|
|
} else if(type == DIAMETER) {
|
2015-03-22 13:07:49 +00:00
|
|
|
if(!other) {
|
2016-04-16 01:07:35 +00:00
|
|
|
result = "⌀" + SS.MmToString(valA);
|
2015-03-22 13:07:49 +00:00
|
|
|
} else {
|
2015-11-06 08:40:12 +00:00
|
|
|
result = "R" + SS.MmToString(valA / 2);
|
2015-03-22 13:07:49 +00:00
|
|
|
}
|
2008-06-11 04:22:52 +00:00
|
|
|
} else {
|
2008-06-14 08:43:38 +00:00
|
|
|
// valA has units of distance
|
2015-11-06 08:40:12 +00:00
|
|
|
result = SS.MmToString(fabs(valA));
|
2008-06-11 04:22:52 +00:00
|
|
|
}
|
|
|
|
if(reference) {
|
2015-11-06 08:40:12 +00:00
|
|
|
result += " REF";
|
2008-06-11 04:22:52 +00:00
|
|
|
}
|
2015-11-06 08:40:12 +00:00
|
|
|
return result;
|
2008-06-11 04:22:52 +00:00
|
|
|
}
|
|
|
|
|
2008-05-07 08:19:37 +00:00
|
|
|
void Constraint::DoLabel(Vector ref, Vector *labelPos, Vector gr, Vector gu) {
|
2016-02-21 19:07:58 +00:00
|
|
|
hStyle hs = disp.style;
|
|
|
|
if(hs.v == 0) hs.v = Style::CONSTRAINT;
|
|
|
|
double th = Style::TextHeight(hs);
|
2009-09-24 15:52:48 +00:00
|
|
|
|
2015-11-06 08:40:12 +00:00
|
|
|
std::string s = Label();
|
2016-02-05 09:28:29 +00:00
|
|
|
double swidth = ssglStrWidth(s, th),
|
2016-04-12 13:38:09 +00:00
|
|
|
sheight = ssglStrCapHeight(th);
|
2009-09-24 15:52:48 +00:00
|
|
|
|
|
|
|
// By default, the reference is from the center; but the style could
|
2009-09-29 11:35:19 +00:00
|
|
|
// specify otherwise if one is present, and it could also specify a
|
|
|
|
// rotation.
|
2009-09-24 15:52:48 +00:00
|
|
|
if(type == COMMENT && disp.style.v) {
|
2009-09-29 11:35:19 +00:00
|
|
|
Style *st = Style::Get(disp.style);
|
|
|
|
// rotation first
|
|
|
|
double rads = st->textAngle*PI/180;
|
|
|
|
double c = cos(rads), s = sin(rads);
|
|
|
|
Vector pr = gr, pu = gu;
|
|
|
|
gr = pr.ScaledBy( c).Plus(pu.ScaledBy(s));
|
|
|
|
gu = pr.ScaledBy(-s).Plus(pu.ScaledBy(c));
|
|
|
|
// then origin
|
|
|
|
int o = st->textOrigin;
|
2009-09-24 15:52:48 +00:00
|
|
|
if(o & Style::ORIGIN_LEFT) ref = ref.Plus(gr.WithMagnitude(swidth/2));
|
|
|
|
if(o & Style::ORIGIN_RIGHT) ref = ref.Minus(gr.WithMagnitude(swidth/2));
|
|
|
|
if(o & Style::ORIGIN_BOT) ref = ref.Plus(gu.WithMagnitude(sheight/2));
|
|
|
|
if(o & Style::ORIGIN_TOP) ref = ref.Minus(gu.WithMagnitude(sheight/2));
|
|
|
|
}
|
|
|
|
|
2008-05-07 08:19:37 +00:00
|
|
|
if(labelPos) {
|
|
|
|
// labelPos is from the top left corner (for the text box used to
|
|
|
|
// edit things), but ref is from the center.
|
2008-06-12 08:58:58 +00:00
|
|
|
*labelPos = ref.Minus(gr.WithMagnitude(swidth/2)).Minus(
|
|
|
|
gu.WithMagnitude(sheight/2));
|
2008-05-07 08:19:37 +00:00
|
|
|
}
|
|
|
|
|
2009-09-24 15:52:48 +00:00
|
|
|
|
2008-05-07 08:19:37 +00:00
|
|
|
if(dogd.drawing) {
|
2016-02-14 20:13:40 +00:00
|
|
|
ssglWriteTextRefCenter(s, th, ref, gr, gu, LineCallback, this);
|
2008-05-07 08:19:37 +00:00
|
|
|
} else {
|
2008-06-12 08:58:58 +00:00
|
|
|
double l = swidth/2 - sheight/2;
|
2008-07-06 07:56:24 +00:00
|
|
|
l = max(l, 5/SS.GW.scale);
|
2008-06-12 08:58:58 +00:00
|
|
|
Point2d a = SS.GW.ProjectPoint(ref.Minus(gr.WithMagnitude(l)));
|
|
|
|
Point2d b = SS.GW.ProjectPoint(ref.Plus (gr.WithMagnitude(l)));
|
|
|
|
double d = dogd.mp.DistanceToLine(a, b.Minus(a), true);
|
|
|
|
|
2009-09-24 15:52:48 +00:00
|
|
|
dogd.dmin = min(dogd.dmin, d - (th / 2));
|
2008-05-26 09:56:50 +00:00
|
|
|
dogd.refp = ref;
|
2008-05-07 08:19:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-27 18:15:06 +00:00
|
|
|
void Constraint::StippledLine(Vector a, Vector b) {
|
2008-05-08 07:30:30 +00:00
|
|
|
glLineStipple(4, 0x5555);
|
|
|
|
glEnable(GL_LINE_STIPPLE);
|
2010-01-27 18:15:06 +00:00
|
|
|
LineDrawOrGetDistance(a, b);
|
2008-05-08 07:30:30 +00:00
|
|
|
glDisable(GL_LINE_STIPPLE);
|
2010-01-27 18:15:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Constraint::DoProjectedPoint(Vector *r) {
|
|
|
|
Vector p = r->ProjectInto(workplane);
|
|
|
|
StippledLine(p, *r);
|
2008-05-08 07:30:30 +00:00
|
|
|
*r = p;
|
|
|
|
}
|
|
|
|
|
2009-09-03 08:13:09 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// There is a rectangular box, aligned to our display axes (projRight, projUp)
|
|
|
|
// centered at ref. This is where a dimension label will be drawn. We want to
|
|
|
|
// draw a line from A to B. If that line would intersect the label box, then
|
|
|
|
// trim the line to leave a gap for it, and return zero. If not, then extend
|
|
|
|
// the line to almost meet the box, and return either positive or negative,
|
|
|
|
// depending whether that extension was from A or from B.
|
|
|
|
//-----------------------------------------------------------------------------
|
2016-04-13 02:45:52 +00:00
|
|
|
int Constraint::DoLineTrimmedAgainstBox(Vector ref, Vector a, Vector b, bool extend) {
|
2016-02-21 19:07:58 +00:00
|
|
|
hStyle hs = disp.style;
|
|
|
|
if(hs.v == 0) hs.v = Style::CONSTRAINT;
|
|
|
|
double th = Style::TextHeight(hs);
|
2009-09-03 08:13:09 +00:00
|
|
|
Vector gu = SS.GW.projUp.WithMagnitude(1),
|
|
|
|
gr = SS.GW.projRight.WithMagnitude(1);
|
|
|
|
|
|
|
|
double pixels = 1.0 / SS.GW.scale;
|
2015-11-06 08:40:12 +00:00
|
|
|
std::string s = Label();
|
2016-02-21 19:07:58 +00:00
|
|
|
double swidth = ssglStrWidth(s, th) + 4*pixels,
|
2016-04-12 13:38:09 +00:00
|
|
|
sheight = ssglStrCapHeight(th) + 8*pixels;
|
2009-09-03 08:13:09 +00:00
|
|
|
|
2016-04-13 02:45:52 +00:00
|
|
|
return DoLineTrimmedAgainstBox(ref, a, b, extend, gr, gu, swidth, sheight);
|
|
|
|
}
|
|
|
|
|
|
|
|
int Constraint::DoLineTrimmedAgainstBox(Vector ref, Vector a, Vector b, bool extend,
|
|
|
|
Vector gr, Vector gu, double swidth, double sheight) {
|
2009-09-03 08:13:09 +00:00
|
|
|
struct {
|
|
|
|
Vector n;
|
|
|
|
double d;
|
|
|
|
} planes[4];
|
|
|
|
// reference pos is the center of box occupied by text; build a rectangle
|
|
|
|
// around that, aligned to axes gr and gu, from four planes will all four
|
|
|
|
// normals pointing inward
|
|
|
|
planes[0].n = gu.ScaledBy(-1); planes[0].d = -(gu.Dot(ref) + sheight/2);
|
|
|
|
planes[1].n = gu; planes[1].d = gu.Dot(ref) - sheight/2;
|
|
|
|
planes[2].n = gr; planes[2].d = gr.Dot(ref) - swidth/2;
|
|
|
|
planes[3].n = gr.ScaledBy(-1); planes[3].d = -(gr.Dot(ref) + swidth/2);
|
|
|
|
|
|
|
|
double tmin = VERY_POSITIVE, tmax = VERY_NEGATIVE;
|
|
|
|
Vector dl = b.Minus(a);
|
|
|
|
|
|
|
|
for(int i = 0; i < 4; i++) {
|
|
|
|
bool parallel;
|
|
|
|
Vector p = Vector::AtIntersectionOfPlaneAndLine(
|
|
|
|
planes[i].n, planes[i].d,
|
|
|
|
a, b, ¶llel);
|
|
|
|
if(parallel) continue;
|
|
|
|
|
|
|
|
int j;
|
|
|
|
for(j = 0; j < 4; j++) {
|
|
|
|
double d = (planes[j].n).Dot(p) - planes[j].d;
|
|
|
|
if(d < -LENGTH_EPS) break;
|
|
|
|
}
|
|
|
|
if(j < 4) continue;
|
|
|
|
|
|
|
|
double t = (p.Minus(a)).DivPivoting(dl);
|
|
|
|
tmin = min(t, tmin);
|
|
|
|
tmax = max(t, tmax);
|
|
|
|
}
|
|
|
|
|
2016-04-13 02:45:52 +00:00
|
|
|
// Both in range; so there's pieces of the line on both sides of the label box.
|
|
|
|
if(tmin >= 0.0 && tmin <= 1.0 && tmax >= 0.0 && tmax <= 1.0) {
|
2009-09-03 08:13:09 +00:00
|
|
|
LineDrawOrGetDistance(a, a.Plus(dl.ScaledBy(tmin)));
|
|
|
|
LineDrawOrGetDistance(a.Plus(dl.ScaledBy(tmax)), b);
|
2016-04-13 02:45:52 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only one intersection in range; so the box is right on top of the endpoint
|
|
|
|
if(tmin >= 0.0 && tmin <= 1.0) {
|
2009-09-03 08:13:09 +00:00
|
|
|
LineDrawOrGetDistance(a, a.Plus(dl.ScaledBy(tmin)));
|
2016-04-13 02:45:52 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Likewise.
|
|
|
|
if(tmax >= 0.0 && tmax <= 1.0) {
|
2009-09-03 08:13:09 +00:00
|
|
|
LineDrawOrGetDistance(a.Plus(dl.ScaledBy(tmax)), b);
|
2016-04-13 02:45:52 +00:00
|
|
|
return 0;
|
2009-09-03 08:13:09 +00:00
|
|
|
}
|
2016-04-13 02:45:52 +00:00
|
|
|
|
|
|
|
// The line does not intersect the label; so the line should get
|
|
|
|
// extended to just barely meet the label.
|
2009-09-03 08:13:09 +00:00
|
|
|
// 0 means the label lies within the line, negative means it's outside
|
|
|
|
// and closer to b, positive means outside and closer to a.
|
2016-04-13 02:45:52 +00:00
|
|
|
if(tmax < 0.0) {
|
|
|
|
if(extend) a = a.Plus(dl.ScaledBy(tmax));
|
|
|
|
LineDrawOrGetDistance(a, b);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(tmin > 1.0) {
|
|
|
|
if(extend) b = a.Plus(dl.ScaledBy(tmin));
|
|
|
|
LineDrawOrGetDistance(a, b);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This will happen if the entire line lies within the box.
|
|
|
|
return 0;
|
2009-09-03 08:13:09 +00:00
|
|
|
}
|
|
|
|
|
2016-04-11 14:21:41 +00:00
|
|
|
void Constraint::DoArrow(Vector p, Vector dir, Vector n, double width, double angle, double da) {
|
|
|
|
dir = dir.WithMagnitude(width / cos(angle));
|
|
|
|
dir = dir.RotatedAbout(n, da);
|
|
|
|
LineDrawOrGetDistance(p, p.Plus(dir.RotatedAbout(n, angle)));
|
|
|
|
LineDrawOrGetDistance(p, p.Plus(dir.RotatedAbout(n, -angle)));
|
|
|
|
}
|
|
|
|
|
2009-09-03 08:13:09 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Draw a line with arrows on both ends, and possibly a gap in the middle for
|
|
|
|
// the dimension. We will use these for most length dimensions. The length
|
|
|
|
// being dimensioned is from A to B; but those points get extended perpendicular
|
|
|
|
// to the line AB, until the line between the extensions crosses ref (the
|
|
|
|
// center of the label).
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void Constraint::DoLineWithArrows(Vector ref, Vector a, Vector b,
|
|
|
|
bool onlyOneExt)
|
|
|
|
{
|
|
|
|
double pixels = 1.0 / SS.GW.scale;
|
|
|
|
|
|
|
|
Vector ab = a.Minus(b);
|
|
|
|
Vector ar = a.Minus(ref);
|
|
|
|
// Normal to a plane containing the line and the label origin.
|
|
|
|
Vector n = ab.Cross(ar);
|
|
|
|
// Within that plane, and normal to the line AB; so that's our extension
|
|
|
|
// line.
|
|
|
|
Vector out = ab.Cross(n).WithMagnitude(1);
|
|
|
|
out = out.ScaledBy(-out.Dot(ar));
|
|
|
|
|
|
|
|
Vector ae = a.Plus(out), be = b.Plus(out);
|
|
|
|
|
|
|
|
// Extension lines extend 10 pixels beyond where the arrows get
|
|
|
|
// drawn (which is at the same offset perpendicular from AB as the
|
|
|
|
// label).
|
|
|
|
LineDrawOrGetDistance(a, ae.Plus(out.WithMagnitude(10*pixels)));
|
|
|
|
if(!onlyOneExt) {
|
|
|
|
LineDrawOrGetDistance(b, be.Plus(out.WithMagnitude(10*pixels)));
|
|
|
|
}
|
|
|
|
|
|
|
|
int within = DoLineTrimmedAgainstBox(ref, ae, be);
|
|
|
|
|
|
|
|
// Arrow heads are 13 pixels long, with an 18 degree half-angle.
|
|
|
|
double theta = 18*PI/180;
|
|
|
|
Vector arrow = (be.Minus(ae)).WithMagnitude(13*pixels);
|
|
|
|
|
|
|
|
if(within != 0) {
|
|
|
|
arrow = arrow.ScaledBy(-1);
|
|
|
|
Vector seg = (be.Minus(ae)).WithMagnitude(18*pixels);
|
|
|
|
if(within < 0) LineDrawOrGetDistance(ae, ae.Minus(seg));
|
|
|
|
if(within > 0) LineDrawOrGetDistance(be, be.Plus(seg));
|
|
|
|
}
|
|
|
|
|
2016-04-11 14:21:41 +00:00
|
|
|
DoArrow(ae, arrow, n, 13.0 * pixels, theta, 0.0);
|
|
|
|
DoArrow(be, arrow.Negated(), n, 13.0 * pixels, theta, 0.0);
|
2009-09-03 08:13:09 +00:00
|
|
|
}
|
|
|
|
|
2008-06-14 11:16:14 +00:00
|
|
|
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);
|
2015-03-29 00:30:52 +00:00
|
|
|
|
2008-06-14 11:16:14 +00:00
|
|
|
LineDrawOrGetDistance(m.Minus(n), m.Plus(n));
|
|
|
|
}
|
|
|
|
|
2009-01-08 17:22:59 +00:00
|
|
|
void Constraint::DoEqualRadiusTicks(hEntity he) {
|
2009-04-19 05:53:16 +00:00
|
|
|
Entity *circ = SK.GetEntity(he);
|
2009-01-08 17:22:59 +00:00
|
|
|
|
2009-04-19 05:53:16 +00:00
|
|
|
Vector center = SK.GetEntity(circ->point[0])->PointGetNum();
|
2009-01-08 17:22:59 +00:00
|
|
|
double r = circ->CircleGetRadiusNum();
|
|
|
|
Quaternion q = circ->Normal()->NormalGetNum();
|
|
|
|
Vector u = q.RotationU(), v = q.RotationV();
|
|
|
|
|
|
|
|
double theta;
|
|
|
|
if(circ->type == Entity::CIRCLE) {
|
|
|
|
theta = PI/2;
|
|
|
|
} else if(circ->type == Entity::ARC_OF_CIRCLE) {
|
|
|
|
double thetaa, thetab, dtheta;
|
|
|
|
circ->ArcGetAngles(&thetaa, &thetab, &dtheta);
|
|
|
|
theta = thetaa + dtheta/2;
|
|
|
|
} else oops();
|
|
|
|
|
|
|
|
Vector d = u.ScaledBy(cos(theta)).Plus(v.ScaledBy(sin(theta)));
|
|
|
|
d = d.ScaledBy(r);
|
|
|
|
Vector p = center.Plus(d);
|
|
|
|
Vector tick = d.WithMagnitude(10/SS.GW.scale);
|
|
|
|
LineDrawOrGetDistance(p.Plus(tick), p.Minus(tick));
|
|
|
|
}
|
|
|
|
|
2008-07-20 12:24:43 +00:00
|
|
|
void Constraint::DoArcForAngle(Vector a0, Vector da, Vector b0, Vector db,
|
2016-04-13 02:45:52 +00:00
|
|
|
Vector offset, Vector *ref, bool trim)
|
2008-07-20 12:24:43 +00:00
|
|
|
{
|
2016-04-13 02:45:52 +00:00
|
|
|
Vector gr = SS.GW.projRight.ScaledBy(1.0);
|
|
|
|
Vector gu = SS.GW.projUp.ScaledBy(1.0);
|
2008-07-20 12:24:43 +00:00
|
|
|
|
|
|
|
if(workplane.v != Entity::FREE_IN_3D.v) {
|
|
|
|
a0 = a0.ProjectInto(workplane);
|
|
|
|
b0 = b0.ProjectInto(workplane);
|
|
|
|
da = da.ProjectVectorInto(workplane);
|
|
|
|
db = db.ProjectVectorInto(workplane);
|
|
|
|
}
|
|
|
|
|
2016-04-11 14:21:41 +00:00
|
|
|
double px = 1.0 / SS.GW.scale;
|
|
|
|
Vector a1 = a0.Plus(da);
|
|
|
|
Vector b1 = b0.Plus(db);
|
|
|
|
|
2009-01-03 12:27:33 +00:00
|
|
|
bool skew;
|
2015-03-29 00:30:52 +00:00
|
|
|
Vector pi = Vector::AtIntersectionOfLines(a0, a0.Plus(da),
|
2009-01-03 12:27:33 +00:00
|
|
|
b0, b0.Plus(db), &skew);
|
|
|
|
|
|
|
|
if(!skew) {
|
2008-07-20 12:24:43 +00:00
|
|
|
*ref = pi.Plus(offset);
|
2009-01-03 12:27:33 +00:00
|
|
|
// We draw in a coordinate system centered at the intersection point.
|
|
|
|
// One basis vector is da, and the other is normal to da and in
|
|
|
|
// the plane that contains our lines (so normal to its normal).
|
2016-04-15 11:57:44 +00:00
|
|
|
da = da.WithMagnitude(1);
|
|
|
|
db = db.WithMagnitude(1);
|
|
|
|
|
2016-04-11 14:21:41 +00:00
|
|
|
Vector norm = da.Cross(db);
|
2016-04-15 11:57:44 +00:00
|
|
|
|
2016-04-11 14:21:41 +00:00
|
|
|
Vector dna = norm.Cross(da).WithMagnitude(1.0);
|
2016-04-15 11:57:44 +00:00
|
|
|
Vector dnb = norm.Cross(db).WithMagnitude(1.0);
|
2009-01-03 12:27:33 +00:00
|
|
|
|
2016-04-15 11:57:44 +00:00
|
|
|
// da and db magnitudes are 1.0
|
|
|
|
double thetaf = acos(da.Dot(db));
|
2008-07-20 12:24:43 +00:00
|
|
|
|
2016-04-15 11:57:44 +00:00
|
|
|
// Calculate median
|
2008-07-20 12:24:43 +00:00
|
|
|
Vector m = da.ScaledBy(cos(thetaf/2)).Plus(
|
|
|
|
dna.ScaledBy(sin(thetaf/2)));
|
2016-04-15 11:57:44 +00:00
|
|
|
Vector rm = (*ref).Minus(pi);
|
|
|
|
|
|
|
|
// Test which side we have to place an arc
|
2008-07-20 12:24:43 +00:00
|
|
|
if(m.Dot(rm) < 0) {
|
|
|
|
da = da.ScaledBy(-1); dna = dna.ScaledBy(-1);
|
2016-04-15 11:57:44 +00:00
|
|
|
db = db.ScaledBy(-1); dnb = dnb.ScaledBy(-1);
|
2008-07-20 12:24:43 +00:00
|
|
|
}
|
|
|
|
|
2016-04-15 11:57:44 +00:00
|
|
|
double rda = rm.Dot(da), rdna = rm.Dot(dna);
|
|
|
|
|
|
|
|
// Introduce minimal arc radius in pixels
|
|
|
|
double r = max(sqrt(rda*rda + rdna*rdna), 15.0 * px);
|
|
|
|
|
2016-04-13 02:45:52 +00:00
|
|
|
hStyle hs = disp.style;
|
|
|
|
if(hs.v == 0) hs.v = Style::CONSTRAINT;
|
|
|
|
double th = Style::TextHeight(hs);
|
|
|
|
double swidth = ssglStrWidth(Label(), th) + 4.0 * px;
|
|
|
|
double sheight = ssglStrCapHeight(th) + 8.0 * px;
|
|
|
|
double textR = sqrt(swidth * swidth + sheight * sheight) / 2.0;
|
|
|
|
*ref = pi.Plus(rm.WithMagnitude(std::max(rm.Magnitude(), 15 * px + textR)));
|
|
|
|
|
2016-04-16 11:58:23 +00:00
|
|
|
// Arrow points
|
|
|
|
Vector apa = da. ScaledBy(r).Plus(pi);
|
|
|
|
Vector apb = da. ScaledBy(r*cos(thetaf)).Plus(
|
|
|
|
dna.ScaledBy(r*sin(thetaf))).Plus(pi);
|
|
|
|
|
|
|
|
double arrowW = 13 * px;
|
|
|
|
double arrowA = 18.0 * PI / 180.0;
|
|
|
|
bool arrowVisible = apb.Minus(apa).Magnitude() > 2.5 * arrowW;
|
|
|
|
// Arrow reversing indicator
|
|
|
|
bool arrowRev = false;
|
|
|
|
|
|
|
|
// The minimal extension length in angular representation
|
|
|
|
double extAngle = 18 * px / r;
|
|
|
|
|
|
|
|
// Arc additional angle
|
2016-04-15 11:57:44 +00:00
|
|
|
double addAngle = 0.0;
|
2016-04-16 11:58:23 +00:00
|
|
|
// Arc start angle
|
|
|
|
double startAngle = 0.0;
|
2016-04-11 14:21:41 +00:00
|
|
|
|
2016-04-15 11:57:44 +00:00
|
|
|
// Arc extension to db.
|
|
|
|
// We have just enlarge angle value.
|
|
|
|
if(HasLabel() && rm.Dot(dnb) > 0.0) {
|
|
|
|
// rm direction projected to plane with u = da, v = dna
|
|
|
|
Vector rmp = da.ScaledBy(rda).Plus(dna.ScaledBy(rdna)).WithMagnitude(1.0);
|
|
|
|
// rmp and db magnitudes are 1.0
|
2016-04-16 11:58:23 +00:00
|
|
|
addAngle = std::max(acos(rmp.Dot(db)), extAngle);
|
2016-04-15 11:57:44 +00:00
|
|
|
|
2016-04-16 11:58:23 +00:00
|
|
|
if(arrowVisible) {
|
|
|
|
startAngle = -extAngle;
|
|
|
|
addAngle += extAngle;
|
|
|
|
arrowRev = true;
|
|
|
|
}
|
|
|
|
}
|
2016-04-15 11:57:44 +00:00
|
|
|
|
|
|
|
// Arc extension to da.
|
|
|
|
// We are enlarge angle value and rewrite basis to align along rm projection.
|
|
|
|
if(HasLabel() && rm.Dot(dna) < 0.0) {
|
|
|
|
// rm direction projected to plane with u = da, v = dna
|
|
|
|
Vector rmp = da.ScaledBy(rda).Plus(dna.ScaledBy(rdna)).WithMagnitude(1.0);
|
|
|
|
// rmp and da magnitudes are 1.0
|
2016-04-16 11:58:23 +00:00
|
|
|
startAngle = -std::max(acos(rmp.Dot(da)), extAngle);
|
|
|
|
addAngle = -startAngle;
|
|
|
|
|
|
|
|
if(arrowVisible) {
|
|
|
|
addAngle += extAngle;
|
|
|
|
arrowRev = true;
|
|
|
|
}
|
2016-04-15 11:57:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Vector prev;
|
|
|
|
int n = 30;
|
|
|
|
for(int i = 0; i <= n; i++) {
|
2016-04-16 11:58:23 +00:00
|
|
|
double theta = startAngle + (i*(thetaf + addAngle))/n;
|
|
|
|
Vector p = da.ScaledBy(r*cos(theta)).Plus(
|
|
|
|
dna.ScaledBy(r*sin(theta))).Plus(pi);
|
2016-04-15 11:57:44 +00:00
|
|
|
if(i > 0) {
|
|
|
|
if(trim) {
|
|
|
|
DoLineTrimmedAgainstBox(*ref, prev, p, false, gr, gu, swidth, sheight);
|
|
|
|
} else {
|
|
|
|
LineDrawOrGetDistance(prev, p);
|
|
|
|
}
|
2016-04-13 02:45:52 +00:00
|
|
|
}
|
2008-07-20 12:24:43 +00:00
|
|
|
prev = p;
|
|
|
|
}
|
|
|
|
|
2016-04-11 14:21:41 +00:00
|
|
|
DoLineExtend(a0, a1, apa, 5.0 * px);
|
|
|
|
DoLineExtend(b0, b1, apb, 5.0 * px);
|
|
|
|
|
|
|
|
// Draw arrows only when we have enough space.
|
2016-04-16 11:58:23 +00:00
|
|
|
if(arrowVisible) {
|
2016-04-11 14:21:41 +00:00
|
|
|
double angleCorr = arrowW / (2.0 * r);
|
2016-04-16 11:58:23 +00:00
|
|
|
if(arrowRev) {
|
|
|
|
dna = dna.ScaledBy(-1.0);
|
|
|
|
angleCorr = -angleCorr;
|
|
|
|
}
|
2016-04-11 14:21:41 +00:00
|
|
|
DoArrow(apa, dna, norm, arrowW, arrowA, angleCorr);
|
|
|
|
DoArrow(apb, dna, norm, arrowW, arrowA, thetaf + PI - angleCorr);
|
|
|
|
}
|
2008-07-20 12:24:43 +00:00
|
|
|
} else {
|
|
|
|
// The lines are skew; no wonderful way to illustrate that.
|
|
|
|
*ref = a0.Plus(b0);
|
|
|
|
*ref = (*ref).ScaledBy(0.5).Plus(disp.offset);
|
2009-07-03 20:55:57 +00:00
|
|
|
gu = gu.WithMagnitude(1);
|
2009-09-24 15:52:48 +00:00
|
|
|
Vector trans =
|
2016-04-12 13:38:09 +00:00
|
|
|
(*ref).Plus(gu.ScaledBy(-1.5*ssglStrCapHeight(Style::DefaultTextHeight())));
|
2016-03-02 17:15:28 +00:00
|
|
|
ssglWriteTextRefCenter("angle between skew lines", Style::DefaultTextHeight(),
|
2016-04-13 02:45:52 +00:00
|
|
|
trans, gr.WithMagnitude(px), gu.WithMagnitude(px), LineCallback, this);
|
2008-07-20 12:24:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-24 13:55:36 +00:00
|
|
|
bool Constraint::IsVisible() const {
|
|
|
|
if(!SS.GW.showConstraints) return false;
|
2009-04-19 05:53:16 +00:00
|
|
|
Group *g = SK.GetGroup(group);
|
2008-04-28 07:18:39 +00:00
|
|
|
// If the group is hidden, then the constraints are hidden and not
|
|
|
|
// able to be selected.
|
2016-03-24 13:55:36 +00:00
|
|
|
if(!(g->visible)) return false;
|
2009-09-29 11:35:19 +00:00
|
|
|
// And likewise if the group is not the active group; except for comments
|
|
|
|
// with an assigned style.
|
|
|
|
if(g->h.v != SS.GW.activeGroup.v && !(type == COMMENT && disp.style.v)) {
|
2016-03-24 13:55:36 +00:00
|
|
|
return false;
|
2009-09-29 11:35:19 +00:00
|
|
|
}
|
|
|
|
if(disp.style.v) {
|
|
|
|
Style *s = Style::Get(disp.style);
|
2016-03-24 13:55:36 +00:00
|
|
|
if(!s->visible) return false;
|
2009-09-29 11:35:19 +00:00
|
|
|
}
|
2016-03-24 13:55:36 +00:00
|
|
|
return true;
|
|
|
|
}
|
2008-04-21 08:16:38 +00:00
|
|
|
|
2016-04-11 14:21:41 +00:00
|
|
|
bool Constraint::DoLineExtend(Vector p0, Vector p1, Vector pt, double salient) {
|
|
|
|
Vector dir = p1.Minus(p0);
|
|
|
|
double k = dir.Dot(pt.Minus(p0)) / dir.Dot(dir);
|
|
|
|
Vector ptOnLine = p0.Plus(dir.ScaledBy(k));
|
|
|
|
|
|
|
|
// Draw projection line.
|
|
|
|
LineDrawOrGetDistance(pt, ptOnLine);
|
|
|
|
|
|
|
|
// Calculate salient direction.
|
|
|
|
Vector sd = dir.WithMagnitude(1.0).ScaledBy(salient);
|
|
|
|
|
|
|
|
Vector from;
|
|
|
|
Vector to;
|
|
|
|
|
|
|
|
if(k < 0.0) {
|
|
|
|
from = p0;
|
|
|
|
to = ptOnLine.Minus(sd);
|
|
|
|
} else if(k > 1.0) {
|
|
|
|
from = p1;
|
|
|
|
to = ptOnLine.Plus(sd);
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Draw extension line.
|
|
|
|
LineDrawOrGetDistance(from, to);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-03-24 13:55:36 +00:00
|
|
|
void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
2016-04-11 14:21:41 +00:00
|
|
|
|
2016-03-24 13:55:36 +00:00
|
|
|
if(!IsVisible()) return;
|
2016-04-11 14:21:41 +00:00
|
|
|
|
2008-04-28 09:40:02 +00:00
|
|
|
// 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);
|
2008-04-14 10:28:32 +00:00
|
|
|
|
|
|
|
switch(type) {
|
|
|
|
case PT_PT_DISTANCE: {
|
2009-04-19 05:53:16 +00:00
|
|
|
Vector ap = SK.GetEntity(ptA)->PointGetNum();
|
|
|
|
Vector bp = SK.GetEntity(ptB)->PointGetNum();
|
2008-04-14 10:28:32 +00:00
|
|
|
|
2008-05-08 07:30:30 +00:00
|
|
|
if(workplane.v != Entity::FREE_IN_3D.v) {
|
|
|
|
DoProjectedPoint(&ap);
|
|
|
|
DoProjectedPoint(&bp);
|
|
|
|
}
|
|
|
|
|
2008-04-14 10:28:32 +00:00
|
|
|
Vector ref = ((ap.Plus(bp)).ScaledBy(0.5)).Plus(disp.offset);
|
|
|
|
|
2009-09-03 08:13:09 +00:00
|
|
|
DoLineWithArrows(ref, ap, bp, false);
|
2008-05-07 08:19:37 +00:00
|
|
|
DoLabel(ref, labelPos, gr, gu);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-01-27 18:15:06 +00:00
|
|
|
case PROJ_PT_DISTANCE: {
|
|
|
|
Vector ap = SK.GetEntity(ptA)->PointGetNum(),
|
|
|
|
bp = SK.GetEntity(ptB)->PointGetNum(),
|
|
|
|
dp = (bp.Minus(ap)),
|
|
|
|
pp = SK.GetEntity(entityA)->VectorGetNum();
|
|
|
|
|
|
|
|
Vector ref = ((ap.Plus(bp)).ScaledBy(0.5)).Plus(disp.offset);
|
|
|
|
|
|
|
|
pp = pp.WithMagnitude(1);
|
|
|
|
double d = dp.Dot(pp);
|
|
|
|
Vector bpp = ap.Plus(pp.ScaledBy(d));
|
|
|
|
StippledLine(ap, bpp);
|
|
|
|
StippledLine(bp, bpp);
|
|
|
|
|
|
|
|
DoLineWithArrows(ref, ap, bpp, false);
|
|
|
|
DoLabel(ref, labelPos, gr, gu);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-06-06 08:46:55 +00:00
|
|
|
case PT_FACE_DISTANCE:
|
2008-05-08 07:30:30 +00:00
|
|
|
case PT_PLANE_DISTANCE: {
|
2009-04-19 05:53:16 +00:00
|
|
|
Vector pt = SK.GetEntity(ptA)->PointGetNum();
|
|
|
|
Entity *enta = SK.GetEntity(entityA);
|
2008-06-06 08:46:55 +00:00
|
|
|
Vector n, p;
|
|
|
|
if(type == PT_PLANE_DISTANCE) {
|
|
|
|
n = enta->Normal()->NormalN();
|
|
|
|
p = enta->WorkplaneGetOffset();
|
|
|
|
} else {
|
|
|
|
n = enta->FaceGetNormalNum();
|
|
|
|
p = enta->FaceGetPointNum();
|
|
|
|
}
|
|
|
|
|
2008-05-08 07:30:30 +00:00
|
|
|
double d = (p.Minus(pt)).Dot(n);
|
|
|
|
Vector closest = pt.Plus(n.WithMagnitude(d));
|
|
|
|
|
|
|
|
Vector ref = ((closest.Plus(pt)).ScaledBy(0.5)).Plus(disp.offset);
|
2009-09-03 08:13:09 +00:00
|
|
|
|
|
|
|
if(!pt.Equals(closest)) {
|
|
|
|
DoLineWithArrows(ref, pt, closest, true);
|
|
|
|
}
|
|
|
|
|
2008-05-08 07:30:30 +00:00
|
|
|
DoLabel(ref, labelPos, gr, gu);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PT_LINE_DISTANCE: {
|
2009-04-19 05:53:16 +00:00
|
|
|
Vector pt = SK.GetEntity(ptA)->PointGetNum();
|
|
|
|
Entity *line = SK.GetEntity(entityA);
|
|
|
|
Vector lA = SK.GetEntity(line->point[0])->PointGetNum();
|
|
|
|
Vector lB = SK.GetEntity(line->point[1])->PointGetNum();
|
2009-09-03 08:13:09 +00:00
|
|
|
Vector dl = lB.Minus(lA);
|
2008-05-08 07:30:30 +00:00
|
|
|
|
|
|
|
if(workplane.v != Entity::FREE_IN_3D.v) {
|
|
|
|
lA = lA.ProjectInto(workplane);
|
|
|
|
lB = lB.ProjectInto(workplane);
|
|
|
|
DoProjectedPoint(&pt);
|
|
|
|
}
|
|
|
|
|
2008-06-14 11:16:14 +00:00
|
|
|
// Find the closest point on the line
|
2009-09-03 08:13:09 +00:00
|
|
|
Vector closest = pt.ClosestPointOnLine(lA, dl);
|
2008-06-14 11:16:14 +00:00
|
|
|
|
2008-05-08 07:30:30 +00:00
|
|
|
Vector ref = ((closest.Plus(pt)).ScaledBy(0.5)).Plus(disp.offset);
|
|
|
|
DoLabel(ref, labelPos, gr, gu);
|
2008-05-08 08:12:23 +00:00
|
|
|
|
2009-09-03 08:13:09 +00:00
|
|
|
if(!pt.Equals(closest)) {
|
|
|
|
DoLineWithArrows(ref, pt, closest, true);
|
2016-03-02 17:15:28 +00:00
|
|
|
|
2016-01-08 05:20:37 +00:00
|
|
|
// Extensions to line
|
|
|
|
double pixels = 1.0 / SS.GW.scale;
|
|
|
|
Vector refClosest = ref.ClosestPointOnLine(lA, dl);
|
|
|
|
double ddl = dl.Dot(dl);
|
|
|
|
if(fabs(ddl) > LENGTH_EPS * LENGTH_EPS) {
|
|
|
|
double t = refClosest.Minus(lA).Dot(dl) / ddl;
|
|
|
|
if(t < 0.0) {
|
|
|
|
LineDrawOrGetDistance(refClosest.Minus(dl.WithMagnitude(10.0 * pixels)), lA);
|
|
|
|
} else if(t > 1.0) {
|
|
|
|
LineDrawOrGetDistance(refClosest.Plus(dl.WithMagnitude(10.0 * pixels)), lB);
|
|
|
|
}
|
|
|
|
}
|
2009-09-03 08:13:09 +00:00
|
|
|
}
|
|
|
|
|
2008-05-08 08:12:23 +00:00
|
|
|
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.
|
2008-06-14 11:16:14 +00:00
|
|
|
Vector lAB = (lA.Minus(lB));
|
2008-05-08 08:12:23 +00:00
|
|
|
double t = (lA.Minus(closest)).DivPivoting(lAB);
|
|
|
|
|
2009-04-19 05:53:16 +00:00
|
|
|
Vector lA = SK.GetEntity(line->point[0])->PointGetNum();
|
|
|
|
Vector lB = SK.GetEntity(line->point[1])->PointGetNum();
|
2008-05-08 08:12:23 +00:00
|
|
|
|
|
|
|
Vector c2 = (lA.ScaledBy(1-t)).Plus(lB.ScaledBy(t));
|
|
|
|
DoProjectedPoint(&c2);
|
|
|
|
}
|
2008-05-08 07:30:30 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-05-07 08:19:37 +00:00
|
|
|
case DIAMETER: {
|
2009-04-19 05:53:16 +00:00
|
|
|
Entity *circle = SK.GetEntity(entityA);
|
|
|
|
Vector center = SK.GetEntity(circle->point[0])->PointGetNum();
|
2009-09-03 08:13:09 +00:00
|
|
|
Quaternion q = SK.GetEntity(circle->normal)->NormalGetNum();
|
|
|
|
Vector n = q.RotationN().WithMagnitude(1);
|
2008-05-12 10:01:44 +00:00
|
|
|
double r = circle->CircleGetRadiusNum();
|
2008-05-07 08:19:37 +00:00
|
|
|
|
2009-09-03 08:13:09 +00:00
|
|
|
Vector ref = center.Plus(disp.offset);
|
|
|
|
// Force the label into the same plane as the circle.
|
|
|
|
ref = ref.Minus(n.ScaledBy(n.Dot(ref) - n.Dot(center)));
|
2008-05-07 08:19:37 +00:00
|
|
|
|
|
|
|
Vector mark = ref.Minus(center);
|
|
|
|
mark = mark.WithMagnitude(mark.Magnitude()-r);
|
2009-09-03 08:13:09 +00:00
|
|
|
DoLineTrimmedAgainstBox(ref, ref, ref.Minus(mark));
|
2008-04-14 10:28:32 +00:00
|
|
|
|
2010-05-23 06:21:42 +00:00
|
|
|
Vector topLeft;
|
|
|
|
DoLabel(ref, &topLeft, gr, gu);
|
|
|
|
if(labelPos) *labelPos = topLeft;
|
2008-04-14 10:28:32 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-04-21 08:16:38 +00:00
|
|
|
case POINTS_COINCIDENT: {
|
2008-04-22 10:53:42 +00:00
|
|
|
if(!dogd.drawing) {
|
|
|
|
for(int i = 0; i < 2; i++) {
|
2009-04-19 05:53:16 +00:00
|
|
|
Vector p = SK.GetEntity(i == 0 ? ptA : ptB)-> PointGetNum();
|
2008-04-22 10:53:42 +00:00
|
|
|
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);
|
2008-05-26 09:56:50 +00:00
|
|
|
dogd.refp = p;
|
2008-04-22 10:53:42 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-03-26 00:34:28 +00:00
|
|
|
if(dogd.drawing) {
|
|
|
|
// Let's adjust the color of this constraint to have the same
|
|
|
|
// rough luma as the point color, so that the constraint does not
|
|
|
|
// stand out in an ugly way.
|
2015-07-10 11:54:39 +00:00
|
|
|
RgbaColor cd = Style::Color(Style::DATUM),
|
2015-03-26 00:34:28 +00:00
|
|
|
cc = Style::Color(Style::CONSTRAINT);
|
|
|
|
// convert from 8-bit color to a vector
|
|
|
|
Vector vd = Vector::From(cd.redF(), cd.greenF(), cd.blueF()),
|
|
|
|
vc = Vector::From(cc.redF(), cc.greenF(), cc.blueF());
|
|
|
|
// and scale the constraint color to have the same magnitude as
|
|
|
|
// the datum color, maybe a bit dimmer
|
|
|
|
vc = vc.WithMagnitude(vd.Magnitude()*0.9);
|
|
|
|
// and set the color to that.
|
|
|
|
ssglColorRGB(RGBf(vc.x, vc.y, vc.z));
|
|
|
|
|
|
|
|
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 = SK.GetEntity(i == 0 ? ptA : ptB)-> PointGetNum();
|
|
|
|
glBegin(GL_QUADS);
|
|
|
|
ssglVertex3v(p.Plus (r).Plus (d));
|
|
|
|
ssglVertex3v(p.Plus (r).Minus(d));
|
|
|
|
ssglVertex3v(p.Minus(r).Minus(d));
|
|
|
|
ssglVertex3v(p.Minus(r).Plus (d));
|
|
|
|
glEnd();
|
|
|
|
}
|
2008-04-22 10:53:42 +00:00
|
|
|
|
2015-03-26 00:34:28 +00:00
|
|
|
}
|
2008-04-21 08:16:38 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-05-08 07:30:30 +00:00
|
|
|
case PT_ON_CIRCLE:
|
2008-04-28 09:40:02 +00:00
|
|
|
case PT_ON_LINE:
|
2008-06-02 03:31:37 +00:00
|
|
|
case PT_ON_FACE:
|
2008-04-21 08:16:38 +00:00
|
|
|
case PT_IN_PLANE: {
|
2008-06-02 03:31:37 +00:00
|
|
|
double s = 8/SS.GW.scale;
|
2009-04-19 05:53:16 +00:00
|
|
|
Vector p = SK.GetEntity(ptA)->PointGetNum();
|
2008-06-02 03:31:37 +00:00
|
|
|
Vector r, d;
|
|
|
|
if(type == PT_ON_FACE) {
|
2009-04-19 05:53:16 +00:00
|
|
|
Vector n = SK.GetEntity(entityA)->FaceGetNormalNum();
|
2008-06-02 03:31:37 +00:00
|
|
|
r = n.Normal(0);
|
|
|
|
d = n.Normal(1);
|
|
|
|
} else if(type == PT_IN_PLANE) {
|
2009-04-20 07:30:09 +00:00
|
|
|
EntityBase *n = SK.GetEntity(entityA)->Normal();
|
2008-06-02 03:31:37 +00:00
|
|
|
r = n->NormalU();
|
|
|
|
d = n->NormalV();
|
|
|
|
} else {
|
|
|
|
r = gr;
|
|
|
|
d = gu;
|
|
|
|
s *= (6.0/8); // draw these a little smaller
|
|
|
|
}
|
|
|
|
r = r.WithMagnitude(s); d = d.WithMagnitude(s);
|
2008-04-21 08:16:38 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-05-04 05:11:52 +00:00
|
|
|
case WHERE_DRAGGED: {
|
|
|
|
Vector p = SK.GetEntity(ptA)->PointGetNum(),
|
|
|
|
u = p.Plus(gu.WithMagnitude(8/SS.GW.scale)).Plus(
|
|
|
|
gr.WithMagnitude(8/SS.GW.scale)),
|
|
|
|
uu = u.Minus(gu.WithMagnitude(5/SS.GW.scale)),
|
|
|
|
ur = u.Minus(gr.WithMagnitude(5/SS.GW.scale));
|
|
|
|
// Draw four little crop marks, uniformly spaced (by ninety
|
|
|
|
// degree rotations) around the point.
|
|
|
|
int i;
|
|
|
|
for(i = 0; i < 4; i++) {
|
|
|
|
LineDrawOrGetDistance(u, uu);
|
|
|
|
LineDrawOrGetDistance(u, ur);
|
|
|
|
u = u.RotatedAbout(p, gn, PI/2);
|
|
|
|
ur = ur.RotatedAbout(p, gn, PI/2);
|
|
|
|
uu = uu.RotatedAbout(p, gn, PI/2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-05-09 05:33:23 +00:00
|
|
|
case SAME_ORIENTATION: {
|
|
|
|
for(int i = 0; i < 2; i++) {
|
2009-04-19 05:53:16 +00:00
|
|
|
Entity *e = SK.GetEntity(i == 0 ? entityA : entityB);
|
2008-05-09 05:33:23 +00:00
|
|
|
Quaternion q = e->NormalGetNum();
|
|
|
|
Vector n = q.RotationN().WithMagnitude(25/SS.GW.scale);
|
|
|
|
Vector u = q.RotationU().WithMagnitude(6/SS.GW.scale);
|
2009-04-19 05:53:16 +00:00
|
|
|
Vector p = SK.GetEntity(e->point[0])->PointGetNum();
|
2008-05-09 05:33:23 +00:00
|
|
|
p = p.Plus(n.WithMagnitude(10/SS.GW.scale));
|
|
|
|
|
|
|
|
LineDrawOrGetDistance(p.Plus(u), p.Minus(u).Plus(n));
|
|
|
|
LineDrawOrGetDistance(p.Minus(u), p.Plus(u).Plus(n));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-07-20 12:24:43 +00:00
|
|
|
case EQUAL_ANGLE: {
|
|
|
|
Vector ref;
|
2009-04-19 05:53:16 +00:00
|
|
|
Entity *a = SK.GetEntity(entityA);
|
|
|
|
Entity *b = SK.GetEntity(entityB);
|
|
|
|
Entity *c = SK.GetEntity(entityC);
|
|
|
|
Entity *d = SK.GetEntity(entityD);
|
2008-07-20 12:24:43 +00:00
|
|
|
|
2016-04-11 14:21:41 +00:00
|
|
|
Vector a0 = a->VectorGetStartPoint();
|
|
|
|
Vector b0 = b->VectorGetStartPoint();
|
|
|
|
Vector c0 = c->VectorGetStartPoint();
|
|
|
|
Vector d0 = d->VectorGetStartPoint();
|
2008-05-17 11:15:14 +00:00
|
|
|
Vector da = a->VectorGetNum();
|
|
|
|
Vector db = b->VectorGetNum();
|
2008-07-20 12:24:43 +00:00
|
|
|
Vector dc = c->VectorGetNum();
|
|
|
|
Vector dd = d->VectorGetNum();
|
2008-05-17 11:15:14 +00:00
|
|
|
|
2016-04-11 14:21:41 +00:00
|
|
|
if(other) {
|
|
|
|
a0 = a0.Plus(da);
|
|
|
|
da = da.ScaledBy(-1);
|
|
|
|
}
|
2008-05-17 11:15:14 +00:00
|
|
|
|
2015-03-29 00:30:52 +00:00
|
|
|
DoArcForAngle(a0, da, b0, db,
|
2016-04-13 02:45:52 +00:00
|
|
|
da.WithMagnitude(40/SS.GW.scale), &ref, /*trim=*/false);
|
2015-03-29 00:30:52 +00:00
|
|
|
DoArcForAngle(c0, dc, d0, dd,
|
2016-04-13 02:45:52 +00:00
|
|
|
dc.WithMagnitude(40/SS.GW.scale), &ref, /*trim=*/false);
|
2008-05-17 11:15:14 +00:00
|
|
|
|
2008-07-20 12:24:43 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-05-17 11:15:14 +00:00
|
|
|
|
2008-07-20 12:24:43 +00:00
|
|
|
case ANGLE: {
|
2009-04-19 05:53:16 +00:00
|
|
|
Entity *a = SK.GetEntity(entityA);
|
|
|
|
Entity *b = SK.GetEntity(entityB);
|
2015-03-29 00:30:52 +00:00
|
|
|
|
2016-04-11 14:21:41 +00:00
|
|
|
Vector a0 = a->VectorGetStartPoint();
|
|
|
|
Vector b0 = b->VectorGetStartPoint();
|
2008-07-20 12:24:43 +00:00
|
|
|
Vector da = a->VectorGetNum();
|
|
|
|
Vector db = b->VectorGetNum();
|
2016-04-11 14:21:41 +00:00
|
|
|
if(other) {
|
|
|
|
a0 = a0.Plus(da);
|
|
|
|
da = da.ScaledBy(-1);
|
|
|
|
}
|
2008-07-20 12:24:43 +00:00
|
|
|
|
|
|
|
Vector ref;
|
2016-04-13 02:45:52 +00:00
|
|
|
DoArcForAngle(a0, da, b0, db, disp.offset, &ref, /*trim=*/true);
|
2008-05-17 11:15:14 +00:00
|
|
|
DoLabel(ref, labelPos, gr, gu);
|
|
|
|
break;
|
2008-07-02 09:21:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case PERPENDICULAR: {
|
2013-08-26 19:36:00 +00:00
|
|
|
Vector u = Vector::From(0, 0, 0), v = Vector::From(0, 0, 0);
|
2008-07-02 09:21:29 +00:00
|
|
|
Vector rn, ru;
|
|
|
|
if(workplane.v == Entity::FREE_IN_3D.v) {
|
|
|
|
rn = gn;
|
|
|
|
ru = gu;
|
|
|
|
} else {
|
2009-04-20 07:30:09 +00:00
|
|
|
EntityBase *normal = SK.GetEntity(workplane)->Normal();
|
2008-07-02 09:21:29 +00:00
|
|
|
rn = normal->NormalN();
|
|
|
|
ru = normal->NormalV(); // ru meaning r_up, not u/v
|
|
|
|
}
|
|
|
|
|
|
|
|
for(int i = 0; i < 2; i++) {
|
2009-04-19 05:53:16 +00:00
|
|
|
Entity *e = SK.GetEntity(i == 0 ? entityA : entityB);
|
2008-07-02 09:21:29 +00:00
|
|
|
|
|
|
|
if(i == 0) {
|
|
|
|
// Calculate orientation of perpendicular sign only
|
|
|
|
// once, so that it's the same both times it's drawn
|
|
|
|
u = e->VectorGetNum();
|
|
|
|
u = u.WithMagnitude(16/SS.GW.scale);
|
|
|
|
v = (rn.Cross(u)).WithMagnitude(16/SS.GW.scale);
|
2009-11-29 02:42:50 +00:00
|
|
|
// a bit of bias to stop it from flickering between the
|
|
|
|
// two possibilities
|
|
|
|
if(fabs(u.Dot(ru)) < fabs(v.Dot(ru)) + LENGTH_EPS) {
|
2015-03-27 15:43:28 +00:00
|
|
|
swap(u, v);
|
2008-07-02 09:21:29 +00:00
|
|
|
}
|
|
|
|
if(u.Dot(ru) < 0) u = u.ScaledBy(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector p = e->VectorGetRefPoint();
|
|
|
|
Vector s = p.Plus(u).Plus(v);
|
|
|
|
LineDrawOrGetDistance(s, s.Plus(v));
|
|
|
|
|
|
|
|
Vector m = s.Plus(v.ScaledBy(0.5));
|
|
|
|
LineDrawOrGetDistance(m, m.Plus(u));
|
|
|
|
}
|
|
|
|
break;
|
2008-07-13 12:44:05 +00:00
|
|
|
}
|
|
|
|
|
2010-05-10 04:14:06 +00:00
|
|
|
case CURVE_CURVE_TANGENT:
|
2008-07-13 12:44:05 +00:00
|
|
|
case CUBIC_LINE_TANGENT:
|
|
|
|
case ARC_LINE_TANGENT: {
|
|
|
|
Vector textAt, u, v;
|
|
|
|
|
|
|
|
if(type == ARC_LINE_TANGENT) {
|
2009-04-19 05:53:16 +00:00
|
|
|
Entity *arc = SK.GetEntity(entityA);
|
|
|
|
Entity *norm = SK.GetEntity(arc->normal);
|
|
|
|
Vector c = SK.GetEntity(arc->point[0])->PointGetNum();
|
2015-03-29 00:30:52 +00:00
|
|
|
Vector p =
|
2009-04-19 05:53:16 +00:00
|
|
|
SK.GetEntity(arc->point[other ? 2 : 1])->PointGetNum();
|
2008-07-13 12:44:05 +00:00
|
|
|
Vector r = p.Minus(c);
|
|
|
|
textAt = p.Plus(r.WithMagnitude(14/SS.GW.scale));
|
|
|
|
u = norm->NormalU();
|
|
|
|
v = norm->NormalV();
|
2010-05-10 04:14:06 +00:00
|
|
|
} else if(type == CUBIC_LINE_TANGENT) {
|
2008-07-13 12:44:05 +00:00
|
|
|
Vector n;
|
|
|
|
if(workplane.v == Entity::FREE_IN_3D.v) {
|
|
|
|
u = gr;
|
|
|
|
v = gu;
|
|
|
|
n = gn;
|
|
|
|
} else {
|
2009-04-20 07:30:09 +00:00
|
|
|
EntityBase *wn = SK.GetEntity(workplane)->Normal();
|
2008-07-13 12:44:05 +00:00
|
|
|
u = wn->NormalU();
|
|
|
|
v = wn->NormalV();
|
|
|
|
n = wn->NormalN();
|
|
|
|
}
|
|
|
|
|
2009-04-19 05:53:16 +00:00
|
|
|
Entity *cubic = SK.GetEntity(entityA);
|
2009-10-21 04:46:01 +00:00
|
|
|
Vector p = other ? cubic->CubicGetFinishNum() :
|
2015-03-29 00:30:52 +00:00
|
|
|
cubic->CubicGetStartNum();
|
2009-04-19 05:53:16 +00:00
|
|
|
Vector dir = SK.GetEntity(entityB)->VectorGetNum();
|
2008-07-13 12:44:05 +00:00
|
|
|
Vector out = n.Cross(dir);
|
|
|
|
textAt = p.Plus(out.WithMagnitude(14/SS.GW.scale));
|
2010-05-10 04:14:06 +00:00
|
|
|
} else {
|
|
|
|
Vector n, dir;
|
|
|
|
EntityBase *wn = SK.GetEntity(workplane)->Normal();
|
|
|
|
u = wn->NormalU();
|
|
|
|
v = wn->NormalV();
|
|
|
|
n = wn->NormalN();
|
|
|
|
EntityBase *eA = SK.GetEntity(entityA);
|
|
|
|
// Big pain; we have to get a vector tangent to the curve
|
|
|
|
// at the shared point, which could be from either a cubic
|
|
|
|
// or an arc.
|
|
|
|
if(other) {
|
|
|
|
textAt = eA->EndpointFinish();
|
|
|
|
if(eA->type == Entity::CUBIC) {
|
|
|
|
dir = eA->CubicGetFinishTangentNum();
|
|
|
|
} else {
|
|
|
|
dir = SK.GetEntity(eA->point[0])->PointGetNum().Minus(
|
|
|
|
SK.GetEntity(eA->point[2])->PointGetNum());
|
|
|
|
dir = n.Cross(dir);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
textAt = eA->EndpointStart();
|
|
|
|
if(eA->type == Entity::CUBIC) {
|
|
|
|
dir = eA->CubicGetStartTangentNum();
|
|
|
|
} else {
|
|
|
|
dir = SK.GetEntity(eA->point[0])->PointGetNum().Minus(
|
|
|
|
SK.GetEntity(eA->point[1])->PointGetNum());
|
|
|
|
dir = n.Cross(dir);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dir = n.Cross(dir);
|
|
|
|
textAt = textAt.Plus(dir.WithMagnitude(14/SS.GW.scale));
|
2008-07-13 12:44:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(dogd.drawing) {
|
2016-03-02 17:15:28 +00:00
|
|
|
ssglWriteTextRefCenter("T", Style::DefaultTextHeight(),
|
2009-09-24 15:52:48 +00:00
|
|
|
textAt, u, v, LineCallback, this);
|
2008-07-13 12:44:05 +00:00
|
|
|
} else {
|
|
|
|
dogd.refp = textAt;
|
|
|
|
Point2d ref = SS.GW.ProjectPoint(dogd.refp);
|
|
|
|
dogd.dmin = min(dogd.dmin, ref.DistanceTo(dogd.mp)-10);
|
|
|
|
}
|
|
|
|
break;
|
2008-05-17 11:15:14 +00:00
|
|
|
}
|
|
|
|
|
2008-05-09 05:33:23 +00:00
|
|
|
case PARALLEL: {
|
|
|
|
for(int i = 0; i < 2; i++) {
|
2009-04-19 05:53:16 +00:00
|
|
|
Entity *e = SK.GetEntity(i == 0 ? entityA : entityB);
|
2008-05-11 10:40:37 +00:00
|
|
|
Vector n = e->VectorGetNum();
|
2008-05-09 05:33:23 +00:00
|
|
|
n = n.WithMagnitude(25/SS.GW.scale);
|
|
|
|
Vector u = (gn.Cross(n)).WithMagnitude(4/SS.GW.scale);
|
|
|
|
Vector p = e->VectorGetRefPoint();
|
|
|
|
|
|
|
|
LineDrawOrGetDistance(p.Plus(u), p.Plus(u).Plus(n));
|
|
|
|
LineDrawOrGetDistance(p.Minus(u), p.Minus(u).Plus(n));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-05-12 10:01:44 +00:00
|
|
|
case EQUAL_RADIUS: {
|
|
|
|
for(int i = 0; i < 2; i++) {
|
2009-01-08 17:22:59 +00:00
|
|
|
DoEqualRadiusTicks(i == 0 ? entityA : entityB);
|
2008-05-12 10:01:44 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-01-08 17:22:59 +00:00
|
|
|
case EQUAL_LINE_ARC_LEN: {
|
2009-04-19 05:53:16 +00:00
|
|
|
Entity *line = SK.GetEntity(entityA);
|
2009-01-08 17:22:59 +00:00
|
|
|
DoEqualLenTicks(
|
2009-04-19 05:53:16 +00:00
|
|
|
SK.GetEntity(line->point[0])->PointGetNum(),
|
|
|
|
SK.GetEntity(line->point[1])->PointGetNum(),
|
2009-01-08 17:22:59 +00:00
|
|
|
gn);
|
|
|
|
|
|
|
|
DoEqualRadiusTicks(entityB);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-05-11 10:40:37 +00:00
|
|
|
case LENGTH_RATIO:
|
2015-10-27 10:28:33 +00:00
|
|
|
case LENGTH_DIFFERENCE:
|
2008-04-22 05:00:49 +00:00
|
|
|
case EQUAL_LENGTH_LINES: {
|
2013-08-26 19:36:00 +00:00
|
|
|
Vector a, b = Vector::From(0, 0, 0);
|
2008-04-22 05:00:49 +00:00
|
|
|
for(int i = 0; i < 2; i++) {
|
2009-04-19 05:53:16 +00:00
|
|
|
Entity *e = SK.GetEntity(i == 0 ? entityA : entityB);
|
|
|
|
a = SK.GetEntity(e->point[0])->PointGetNum();
|
|
|
|
b = SK.GetEntity(e->point[1])->PointGetNum();
|
2008-06-14 11:16:14 +00:00
|
|
|
|
|
|
|
if(workplane.v != Entity::FREE_IN_3D.v) {
|
|
|
|
DoProjectedPoint(&a);
|
|
|
|
DoProjectedPoint(&b);
|
|
|
|
}
|
|
|
|
|
|
|
|
DoEqualLenTicks(a, b, gn);
|
2008-04-22 05:00:49 +00:00
|
|
|
}
|
2015-10-27 10:28:33 +00:00
|
|
|
if((type == LENGTH_RATIO) || (type == LENGTH_DIFFERENCE)) {
|
2008-05-11 10:40:37 +00:00
|
|
|
Vector ref = ((a.Plus(b)).ScaledBy(0.5)).Plus(disp.offset);
|
|
|
|
DoLabel(ref, labelPos, gr, gu);
|
|
|
|
}
|
2008-04-22 05:00:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-06-14 11:16:14 +00:00
|
|
|
case EQ_LEN_PT_LINE_D: {
|
2009-04-19 05:53:16 +00:00
|
|
|
Entity *forLen = SK.GetEntity(entityA);
|
|
|
|
Vector a = SK.GetEntity(forLen->point[0])->PointGetNum(),
|
|
|
|
b = SK.GetEntity(forLen->point[1])->PointGetNum();
|
2008-06-14 11:16:14 +00:00
|
|
|
if(workplane.v != Entity::FREE_IN_3D.v) {
|
|
|
|
DoProjectedPoint(&a);
|
|
|
|
DoProjectedPoint(&b);
|
|
|
|
}
|
|
|
|
DoEqualLenTicks(a, b, gn);
|
|
|
|
|
2009-04-19 05:53:16 +00:00
|
|
|
Entity *ln = SK.GetEntity(entityB);
|
|
|
|
Vector la = SK.GetEntity(ln->point[0])->PointGetNum(),
|
|
|
|
lb = SK.GetEntity(ln->point[1])->PointGetNum();
|
|
|
|
Vector pt = SK.GetEntity(ptA)->PointGetNum();
|
2008-06-14 11:16:14 +00:00
|
|
|
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++) {
|
2009-04-19 05:53:16 +00:00
|
|
|
Entity *ln = SK.GetEntity(i == 0 ? entityA : entityB);
|
|
|
|
Vector la = SK.GetEntity(ln->point[0])->PointGetNum(),
|
|
|
|
lb = SK.GetEntity(ln->point[1])->PointGetNum();
|
|
|
|
Entity *pte = SK.GetEntity(i == 0 ? ptA : ptB);
|
2008-06-14 11:16:14 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2008-05-13 10:38:21 +00:00
|
|
|
{
|
|
|
|
case SYMMETRIC:
|
2013-10-19 05:36:45 +00:00
|
|
|
Vector n;
|
2009-04-19 05:53:16 +00:00
|
|
|
n = SK.GetEntity(entityA)->Normal()->NormalN(); goto s;
|
2008-05-13 10:38:21 +00:00
|
|
|
case SYMMETRIC_HORIZ:
|
2009-04-19 05:53:16 +00:00
|
|
|
n = SK.GetEntity(workplane)->Normal()->NormalU(); goto s;
|
2008-05-13 10:38:21 +00:00
|
|
|
case SYMMETRIC_VERT:
|
2009-04-19 05:53:16 +00:00
|
|
|
n = SK.GetEntity(workplane)->Normal()->NormalV(); goto s;
|
2008-07-02 06:59:49 +00:00
|
|
|
case SYMMETRIC_LINE: {
|
2009-04-19 05:53:16 +00:00
|
|
|
Entity *ln = SK.GetEntity(entityA);
|
|
|
|
Vector la = SK.GetEntity(ln->point[0])->PointGetNum(),
|
|
|
|
lb = SK.GetEntity(ln->point[1])->PointGetNum();
|
2008-07-02 06:59:49 +00:00
|
|
|
la = la.ProjectInto(workplane);
|
|
|
|
lb = lb.ProjectInto(workplane);
|
|
|
|
n = lb.Minus(la);
|
2009-04-19 05:53:16 +00:00
|
|
|
Vector nw = SK.GetEntity(workplane)->Normal()->NormalN();
|
2008-07-02 06:59:49 +00:00
|
|
|
n = n.RotatedAbout(nw, PI/2);
|
|
|
|
goto s;
|
|
|
|
}
|
2008-05-13 10:38:21 +00:00
|
|
|
s:
|
2009-04-19 05:53:16 +00:00
|
|
|
Vector a = SK.GetEntity(ptA)->PointGetNum();
|
|
|
|
Vector b = SK.GetEntity(ptB)->PointGetNum();
|
2008-07-02 06:59:49 +00:00
|
|
|
|
2008-04-30 08:14:32 +00:00
|
|
|
for(int i = 0; i < 2; i++) {
|
|
|
|
Vector tail = (i == 0) ? a : b;
|
|
|
|
Vector d = (i == 0) ? b : a;
|
|
|
|
d = d.Minus(tail);
|
|
|
|
// Project the direction in which the arrow is drawn normal
|
|
|
|
// to the symmetry plane; for projected symmetry constraints,
|
|
|
|
// they might not be in the same direction, even when the
|
|
|
|
// constraint is fully solved.
|
|
|
|
d = n.ScaledBy(d.Dot(n));
|
|
|
|
d = d.WithMagnitude(20/SS.GW.scale);
|
|
|
|
Vector tip = tail.Plus(d);
|
|
|
|
|
|
|
|
LineDrawOrGetDistance(tail, tip);
|
|
|
|
d = d.WithMagnitude(9/SS.GW.scale);
|
|
|
|
LineDrawOrGetDistance(tip, tip.Minus(d.RotatedAbout(gn, 0.6)));
|
|
|
|
LineDrawOrGetDistance(tip, tip.Minus(d.RotatedAbout(gn, -0.6)));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case AT_MIDPOINT:
|
2008-04-23 07:29:19 +00:00
|
|
|
case HORIZONTAL:
|
|
|
|
case VERTICAL:
|
|
|
|
if(entityA.v) {
|
2008-05-03 03:33:35 +00:00
|
|
|
Vector r, u, n;
|
|
|
|
if(workplane.v == Entity::FREE_IN_3D.v) {
|
|
|
|
r = gr; u = gu; n = gn;
|
|
|
|
} else {
|
2009-04-19 05:53:16 +00:00
|
|
|
r = SK.GetEntity(workplane)->Normal()->NormalU();
|
|
|
|
u = SK.GetEntity(workplane)->Normal()->NormalV();
|
2008-05-03 03:33:35 +00:00
|
|
|
n = r.Cross(u);
|
|
|
|
}
|
2008-04-30 08:14:32 +00:00
|
|
|
// For "at midpoint", this branch is always taken.
|
2009-04-19 05:53:16 +00:00
|
|
|
Entity *e = SK.GetEntity(entityA);
|
|
|
|
Vector a = SK.GetEntity(e->point[0])->PointGetNum();
|
|
|
|
Vector b = SK.GetEntity(e->point[1])->PointGetNum();
|
2008-04-23 07:29:19 +00:00
|
|
|
Vector m = (a.ScaledBy(0.5)).Plus(b.ScaledBy(0.5));
|
2008-05-03 03:33:35 +00:00
|
|
|
Vector offset = (a.Minus(b)).Cross(n);
|
2008-04-30 08:14:32 +00:00
|
|
|
offset = offset.WithMagnitude(13/SS.GW.scale);
|
2008-05-01 06:53:50 +00:00
|
|
|
// Draw midpoint constraint on other side of line, so that
|
|
|
|
// a line can be midpoint and horizontal at same time.
|
|
|
|
if(type == AT_MIDPOINT) offset = offset.ScaledBy(-1);
|
2008-04-23 07:29:19 +00:00
|
|
|
|
|
|
|
if(dogd.drawing) {
|
2013-08-26 18:58:35 +00:00
|
|
|
const char *s = (type == HORIZONTAL) ? "H" : (
|
|
|
|
(type == VERTICAL) ? "V" : (
|
|
|
|
(type == AT_MIDPOINT) ? "M" : NULL));
|
2009-07-03 20:55:57 +00:00
|
|
|
|
2016-03-02 17:15:28 +00:00
|
|
|
ssglWriteTextRefCenter(s, Style::DefaultTextHeight(),
|
2009-09-24 15:52:48 +00:00
|
|
|
m.Plus(offset), r, u, LineCallback, this);
|
2008-04-23 07:29:19 +00:00
|
|
|
} else {
|
2008-05-26 09:56:50 +00:00
|
|
|
dogd.refp = m.Plus(offset);
|
|
|
|
Point2d ref = SS.GW.ProjectPoint(dogd.refp);
|
2008-04-23 07:29:19 +00:00
|
|
|
dogd.dmin = min(dogd.dmin, ref.DistanceTo(dogd.mp)-10);
|
|
|
|
}
|
|
|
|
} else {
|
2009-04-19 05:53:16 +00:00
|
|
|
Vector a = SK.GetEntity(ptA)->PointGetNum();
|
|
|
|
Vector b = SK.GetEntity(ptB)->PointGetNum();
|
2008-04-23 07:46:24 +00:00
|
|
|
|
2009-04-19 05:53:16 +00:00
|
|
|
Entity *w = SK.GetEntity(workplane);
|
2008-05-05 11:17:00 +00:00
|
|
|
Vector cu = w->Normal()->NormalU();
|
|
|
|
Vector cv = w->Normal()->NormalV();
|
|
|
|
Vector cn = w->Normal()->NormalN();
|
2008-04-23 07:29:19 +00:00
|
|
|
|
|
|
|
int i;
|
|
|
|
for(i = 0; i < 2; i++) {
|
|
|
|
Vector o = (i == 0) ? a : b;
|
2008-04-23 07:46:24 +00:00
|
|
|
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);
|
|
|
|
|
2008-04-23 07:29:19 +00:00
|
|
|
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);
|
2013-10-22 04:45:06 +00:00
|
|
|
ssglVertex3v((c.Plus(d)).Plus(dp));
|
|
|
|
ssglVertex3v((c.Minus(d)).Plus(dp));
|
|
|
|
ssglVertex3v((c.Minus(d)).Minus(dp));
|
|
|
|
ssglVertex3v((c.Plus(d)).Minus(dp));
|
2008-04-23 07:29:19 +00:00
|
|
|
glEnd();
|
|
|
|
} else {
|
|
|
|
Point2d ref = SS.GW.ProjectPoint(c);
|
|
|
|
dogd.dmin = min(dogd.dmin, ref.DistanceTo(dogd.mp)-6);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2009-09-29 11:35:19 +00:00
|
|
|
case COMMENT: {
|
2015-03-26 00:34:28 +00:00
|
|
|
if(dogd.drawing && disp.style.v) {
|
2015-03-22 13:39:12 +00:00
|
|
|
ssglLineWidth(Style::Width(disp.style));
|
2013-10-22 04:45:06 +00:00
|
|
|
ssglColorRGB(Style::Color(disp.style));
|
2009-09-24 15:52:48 +00:00
|
|
|
}
|
2009-09-29 11:35:19 +00:00
|
|
|
Vector u, v;
|
|
|
|
if(workplane.v == Entity::FREE_IN_3D.v) {
|
|
|
|
u = gr;
|
|
|
|
v = gu;
|
|
|
|
} else {
|
|
|
|
EntityBase *norm = SK.GetEntity(workplane)->Normal();
|
|
|
|
u = norm->NormalU();
|
|
|
|
v = norm->NormalV();
|
|
|
|
}
|
|
|
|
DoLabel(disp.offset, labelPos, u, v);
|
2008-06-12 08:58:58 +00:00
|
|
|
break;
|
2009-09-29 11:35:19 +00:00
|
|
|
}
|
2008-06-12 08:58:58 +00:00
|
|
|
|
2008-04-14 10:28:32 +00:00
|
|
|
default: oops();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Constraint::Draw(void) {
|
|
|
|
dogd.drawing = true;
|
2009-07-03 20:55:57 +00:00
|
|
|
dogd.sel = NULL;
|
2016-02-21 19:07:58 +00:00
|
|
|
hStyle hs = disp.style;
|
|
|
|
if(hs.v == 0) hs.v = Style::CONSTRAINT;
|
2009-09-17 07:32:36 +00:00
|
|
|
|
2016-02-21 19:07:58 +00:00
|
|
|
ssglLineWidth(Style::Width(hs));
|
|
|
|
ssglColorRGB(Style::Color(hs));
|
2009-09-17 07:32:36 +00:00
|
|
|
|
2008-04-21 10:12:04 +00:00
|
|
|
DrawOrGetDistance(NULL);
|
2008-04-14 10:28:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
double Constraint::GetDistance(Point2d mp) {
|
|
|
|
dogd.drawing = false;
|
2009-07-03 20:55:57 +00:00
|
|
|
dogd.sel = NULL;
|
2008-04-14 10:28:32 +00:00
|
|
|
dogd.mp = mp;
|
|
|
|
dogd.dmin = 1e12;
|
|
|
|
|
2008-04-21 10:12:04 +00:00
|
|
|
DrawOrGetDistance(NULL);
|
2015-03-29 00:30:52 +00:00
|
|
|
|
2008-04-14 10:28:32 +00:00
|
|
|
return dogd.dmin;
|
|
|
|
}
|
|
|
|
|
2008-04-21 10:12:04 +00:00
|
|
|
Vector Constraint::GetLabelPos(void) {
|
|
|
|
dogd.drawing = false;
|
2009-07-03 20:55:57 +00:00
|
|
|
dogd.sel = NULL;
|
2008-04-21 10:12:04 +00:00
|
|
|
dogd.mp.x = 0; dogd.mp.y = 0;
|
|
|
|
dogd.dmin = 1e12;
|
|
|
|
|
|
|
|
Vector p;
|
|
|
|
DrawOrGetDistance(&p);
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2008-05-26 09:56:50 +00:00
|
|
|
Vector Constraint::GetReferencePos(void) {
|
|
|
|
dogd.drawing = false;
|
2009-07-03 20:55:57 +00:00
|
|
|
dogd.sel = NULL;
|
2008-05-26 09:56:50 +00:00
|
|
|
|
|
|
|
dogd.refp = SS.GW.offset.ScaledBy(-1);
|
|
|
|
DrawOrGetDistance(NULL);
|
|
|
|
|
|
|
|
return dogd.refp;
|
|
|
|
}
|
|
|
|
|
2009-07-03 20:55:57 +00:00
|
|
|
void Constraint::GetEdges(SEdgeList *sel) {
|
|
|
|
dogd.drawing = true;
|
|
|
|
dogd.sel = sel;
|
|
|
|
DrawOrGetDistance(NULL);
|
|
|
|
dogd.sel = NULL;
|
|
|
|
}
|
|
|
|
|
2016-03-25 08:45:49 +00:00
|
|
|
bool Constraint::IsStylable() {
|
|
|
|
if(type == COMMENT) return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|