Draw extension lines for angle constraints between line segments.

pull/4/head
EvilSpirit 2016-04-11 20:21:41 +06:00 committed by whitequark
parent 1098e598ae
commit 07f3ab95e4
2 changed files with 80 additions and 18 deletions

View File

@ -227,6 +227,13 @@ int Constraint::DoLineTrimmedAgainstBox(Vector ref, Vector a, Vector b) {
return within;
}
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)));
}
//-----------------------------------------------------------------------------
// 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
@ -271,11 +278,8 @@ void Constraint::DoLineWithArrows(Vector ref, Vector a, Vector b,
if(within > 0) LineDrawOrGetDistance(be, be.Plus(seg));
}
LineDrawOrGetDistance(ae, ae.Plus(arrow.RotatedAbout(n, theta)));
LineDrawOrGetDistance(ae, ae.Plus(arrow.RotatedAbout(n, -theta)));
arrow = arrow.ScaledBy(-1);
LineDrawOrGetDistance(be, be.Plus(arrow.RotatedAbout(n, theta)));
LineDrawOrGetDistance(be, be.Plus(arrow.RotatedAbout(n, -theta)));
DoArrow(ae, arrow, n, 13.0 * pixels, theta, 0.0);
DoArrow(be, arrow.Negated(), n, 13.0 * pixels, theta, 0.0);
}
void Constraint::DoEqualLenTicks(Vector a, Vector b, Vector gn) {
@ -323,6 +327,10 @@ void Constraint::DoArcForAngle(Vector a0, Vector da, Vector b0, Vector db,
db = db.ProjectVectorInto(workplane);
}
double px = 1.0 / SS.GW.scale;
Vector a1 = a0.Plus(da);
Vector b1 = b0.Plus(db);
bool skew;
Vector pi = Vector::AtIntersectionOfLines(a0, a0.Plus(da),
b0, b0.Plus(db), &skew);
@ -332,12 +340,13 @@ void Constraint::DoArcForAngle(Vector a0, Vector da, Vector b0, Vector db,
// 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).
Vector dna = (da.Cross(db)).Cross(da);
da = da.WithMagnitude(1); dna = dna.WithMagnitude(1);
Vector norm = da.Cross(db);
Vector dna = norm.Cross(da).WithMagnitude(1.0);
da = da.WithMagnitude(1);
Vector rm = (*ref).Minus(pi);
double rda = rm.Dot(da), rdna = rm.Dot(dna);
double r = sqrt(rda*rda + rdna*rdna);
double r = max(sqrt(rda*rda + rdna*rdna), 15.0 * px);
double c = (da.Dot(db))/(da.Magnitude()*db.Magnitude());
double thetaf = acos(c);
@ -348,6 +357,8 @@ void Constraint::DoArcForAngle(Vector a0, Vector da, Vector b0, Vector db,
}
Vector prev = da.ScaledBy(r).Plus(pi);
Vector apa = prev;
int i, n = 30;
for(i = 0; i <= n; i++) {
double theta = (i*thetaf)/n;
@ -357,6 +368,20 @@ void Constraint::DoArcForAngle(Vector a0, Vector da, Vector b0, Vector db,
prev = p;
}
Vector apb = prev;
DoLineExtend(a0, a1, apa, 5.0 * px);
DoLineExtend(b0, b1, apb, 5.0 * px);
double arrowW = 13 * px;
double arrowA = 18.0 * PI / 180.0;
// Draw arrows only when we have enough space.
if(apb.Minus(apa).Magnitude() > 2.5 * arrowW) {
double angleCorr = arrowW / (2.0 * r);
DoArrow(apa, dna, norm, arrowW, arrowA, angleCorr);
DoArrow(apb, dna, norm, arrowW, arrowA, thetaf + PI - angleCorr);
}
// The elliptical approximation isn't exactly right, but the correct
// calculation (against the bounding box of the text) would be rather
// complex and this looks pretty good.
@ -396,6 +421,35 @@ bool Constraint::IsVisible() const {
return true;
}
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;
}
void Constraint::DrawOrGetDistance(Vector *labelPos) {
if(!IsVisible()) return;
@ -656,16 +710,19 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
Entity *c = SK.GetEntity(entityC);
Entity *d = SK.GetEntity(entityD);
Vector a0 = a->VectorGetRefPoint();
Vector b0 = b->VectorGetRefPoint();
Vector c0 = c->VectorGetRefPoint();
Vector d0 = d->VectorGetRefPoint();
Vector a0 = a->VectorGetStartPoint();
Vector b0 = b->VectorGetStartPoint();
Vector c0 = c->VectorGetStartPoint();
Vector d0 = d->VectorGetStartPoint();
Vector da = a->VectorGetNum();
Vector db = b->VectorGetNum();
Vector dc = c->VectorGetNum();
Vector dd = d->VectorGetNum();
if(other) da = da.ScaledBy(-1);
if(other) {
a0 = a0.Plus(da);
da = da.ScaledBy(-1);
}
DoArcForAngle(a0, da, b0, db,
da.WithMagnitude(40/SS.GW.scale), &ref);
@ -679,11 +736,14 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
Entity *a = SK.GetEntity(entityA);
Entity *b = SK.GetEntity(entityB);
Vector a0 = a->VectorGetRefPoint();
Vector b0 = b->VectorGetRefPoint();
Vector a0 = a->VectorGetStartPoint();
Vector b0 = b->VectorGetStartPoint();
Vector da = a->VectorGetNum();
Vector db = b->VectorGetNum();
if(other) da = da.ScaledBy(-1);
if(other) {
a0 = a0.Plus(da);
da = da.ScaledBy(-1);
}
Vector ref;
DoArcForAngle(a0, da, b0, db, disp.offset, &ref);

View File

@ -688,8 +688,10 @@ public:
void DrawOrGetDistance(Vector *labelPos);
double EllipticalInterpolation(double rx, double ry, double theta);
std::string Label(void);
bool DoLineExtend(Vector p0, Vector p1, Vector pt, double salient);
void DoArcForAngle(Vector a0, Vector da, Vector b0, Vector db,
Vector offset, Vector *ref);
void DoArrow(Vector p, Vector dir, Vector n, double width, double angle, double da);
void DoLineWithArrows(Vector ref, Vector a, Vector b, bool onlyOneExt);
int DoLineTrimmedAgainstBox(Vector ref, Vector a, Vector b);
void DoLabel(Vector ref, Vector *labelPos, Vector gr, Vector gu);