2008-06-06 08:14:37 +00:00
|
|
|
#include "solvespace.h"
|
|
|
|
|
2009-04-19 04:28:21 +00:00
|
|
|
char *Entity::DescriptionString(void) {
|
|
|
|
if(h.isFromRequest()) {
|
2009-04-19 05:53:16 +00:00
|
|
|
Request *r = SK.GetRequest(h.request());
|
2009-04-19 04:28:21 +00:00
|
|
|
return r->DescriptionString();
|
|
|
|
} else {
|
2009-04-19 05:53:16 +00:00
|
|
|
Group *g = SK.GetGroup(h.group());
|
2009-04-19 04:28:21 +00:00
|
|
|
return g->DescriptionString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-18 08:14:15 +00:00
|
|
|
void Entity::FatLineEndcap(Vector p, Vector u, Vector v) {
|
|
|
|
// A table of cos and sin of (pi*i/10 + pi/2), as i goes from 0 to 10
|
|
|
|
static const double Circle[11][2] = {
|
|
|
|
{ 0.0000, 1.0000 },
|
|
|
|
{ -0.3090, 0.9511 },
|
|
|
|
{ -0.5878, 0.8090 },
|
|
|
|
{ -0.8090, 0.5878 },
|
|
|
|
{ -0.9511, 0.3090 },
|
|
|
|
{ -1.0000, 0.0000 },
|
|
|
|
{ -0.9511, -0.3090 },
|
|
|
|
{ -0.8090, -0.5878 },
|
|
|
|
{ -0.5878, -0.8090 },
|
|
|
|
{ -0.3090, -0.9511 },
|
|
|
|
{ 0.0000, -1.0000 },
|
|
|
|
};
|
|
|
|
glBegin(GL_TRIANGLE_FAN);
|
|
|
|
for(int i = 0; i <= 10; i++) {
|
|
|
|
double c = Circle[i][0], s = Circle[i][1];
|
|
|
|
glxVertex3v(p.Plus(u.ScaledBy(c)).Plus(v.ScaledBy(s)));
|
|
|
|
}
|
|
|
|
glEnd();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Entity::FatLine(Vector a, Vector b) {
|
|
|
|
// The half-width of the line we're drawing.
|
|
|
|
double hw = (dogd.lineWidth/SS.GW.scale) / 2;
|
|
|
|
Vector ab = b.Minus(a);
|
|
|
|
Vector gn = (SS.GW.projRight).Cross(SS.GW.projUp);
|
|
|
|
Vector abn = (ab.Cross(gn)).WithMagnitude(1);
|
|
|
|
abn = abn.Minus(gn.ScaledBy(gn.Dot(abn)));
|
|
|
|
// So now abn is normal to the projection of ab into the screen, so the
|
|
|
|
// line will always have constant thickness as the view is rotated.
|
|
|
|
|
|
|
|
abn = abn.WithMagnitude(hw);
|
|
|
|
ab = gn.Cross(abn);
|
|
|
|
ab = ab. WithMagnitude(hw);
|
|
|
|
|
|
|
|
// The body of a line is a quad
|
|
|
|
glBegin(GL_QUADS);
|
|
|
|
glxVertex3v(a.Minus(abn));
|
|
|
|
glxVertex3v(b.Minus(abn));
|
|
|
|
glxVertex3v(b.Plus (abn));
|
|
|
|
glxVertex3v(a.Plus (abn));
|
|
|
|
glEnd();
|
|
|
|
// And the line has two semi-circular end caps.
|
|
|
|
FatLineEndcap(a, ab, abn);
|
|
|
|
FatLineEndcap(b, ab.ScaledBy(-1), abn);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Entity::LineDrawOrGetDistance(Vector a, Vector b, bool maybeFat) {
|
2008-06-06 08:14:37 +00:00
|
|
|
if(dogd.drawing) {
|
2008-06-11 04:22:52 +00:00
|
|
|
// Draw lines from active group in front of those from previous
|
2008-07-10 05:26:08 +00:00
|
|
|
glxDepthRangeOffset((group.v == SS.GW.activeGroup.v) ? 4 : 3);
|
2009-09-18 08:14:15 +00:00
|
|
|
// Narrow lines are drawn as lines, but fat lines must be drawn as
|
|
|
|
// filled polygons, to get the line join style right.
|
|
|
|
if(!maybeFat || dogd.lineWidth < 3) {
|
|
|
|
glBegin(GL_LINES);
|
|
|
|
glxVertex3v(a);
|
|
|
|
glxVertex3v(b);
|
|
|
|
glEnd();
|
|
|
|
} else {
|
|
|
|
FatLine(a, b);
|
|
|
|
}
|
|
|
|
|
2008-06-17 19:12:25 +00:00
|
|
|
glxDepthRangeOffset(0);
|
2008-06-06 08:14:37 +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);
|
2008-06-11 04:22:52 +00:00
|
|
|
// A little bit easier to select in the active group
|
|
|
|
if(group.v == SS.GW.activeGroup.v) d -= 1;
|
2008-06-06 08:14:37 +00:00
|
|
|
dogd.dmin = min(dogd.dmin, d);
|
|
|
|
}
|
|
|
|
dogd.refp = (a.Plus(b)).ScaledBy(0.5);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Entity::DrawAll(void) {
|
|
|
|
// This handles points and line segments as a special case, because I
|
|
|
|
// seem to be able to get a huge speedup that way, by consolidating
|
|
|
|
// stuff to gl.
|
|
|
|
int i;
|
|
|
|
if(SS.GW.showPoints) {
|
|
|
|
double s = 3.5/SS.GW.scale;
|
|
|
|
Vector r = SS.GW.projRight.ScaledBy(s);
|
|
|
|
Vector d = SS.GW.projUp.ScaledBy(s);
|
2009-09-17 07:32:36 +00:00
|
|
|
glxColorRGB(Style::Color(Style::DATUM));
|
2008-06-17 19:12:25 +00:00
|
|
|
glxDepthRangeOffset(6);
|
2008-06-06 08:14:37 +00:00
|
|
|
glBegin(GL_QUADS);
|
2009-04-19 05:53:16 +00:00
|
|
|
for(i = 0; i < SK.entity.n; i++) {
|
|
|
|
Entity *e = &(SK.entity.elem[i]);
|
2008-06-06 08:14:37 +00:00
|
|
|
if(!e->IsPoint()) continue;
|
2009-04-19 05:53:16 +00:00
|
|
|
if(!(SK.GetGroup(e->group)->visible)) continue;
|
2008-06-09 09:03:21 +00:00
|
|
|
if(SS.GroupsInOrder(SS.GW.activeGroup, e->group)) continue;
|
2008-06-13 04:41:27 +00:00
|
|
|
if(e->forceHidden) continue;
|
2008-06-06 08:14:37 +00:00
|
|
|
|
|
|
|
Vector v = e->PointGetNum();
|
2009-01-04 12:01:46 +00:00
|
|
|
|
2009-09-17 07:32:36 +00:00
|
|
|
// If we're analyzing the sketch to show the degrees of freedom,
|
|
|
|
// then we draw big colored squares over the points that are
|
|
|
|
// free to move.
|
2009-01-04 12:01:46 +00:00
|
|
|
bool free = false;
|
|
|
|
if(e->type == POINT_IN_3D) {
|
2009-04-19 05:53:16 +00:00
|
|
|
Param *px = SK.GetParam(e->param[0]),
|
|
|
|
*py = SK.GetParam(e->param[1]),
|
|
|
|
*pz = SK.GetParam(e->param[2]);
|
2009-01-04 12:01:46 +00:00
|
|
|
|
|
|
|
free = (px->free) || (py->free) || (pz->free);
|
|
|
|
} else if(e->type == POINT_IN_2D) {
|
2009-04-19 05:53:16 +00:00
|
|
|
Param *pu = SK.GetParam(e->param[0]),
|
|
|
|
*pv = SK.GetParam(e->param[1]);
|
2009-01-04 12:01:46 +00:00
|
|
|
|
|
|
|
free = (pu->free) || (pv->free);
|
|
|
|
}
|
|
|
|
if(free) {
|
|
|
|
Vector re = r.ScaledBy(2.5), de = d.ScaledBy(2.5);
|
|
|
|
|
2009-09-17 07:32:36 +00:00
|
|
|
glxColorRGB(Style::Color(Style::ANALYZE));
|
2009-01-04 12:01:46 +00:00
|
|
|
glxVertex3v(v.Plus (re).Plus (de));
|
|
|
|
glxVertex3v(v.Plus (re).Minus(de));
|
|
|
|
glxVertex3v(v.Minus(re).Minus(de));
|
|
|
|
glxVertex3v(v.Minus(re).Plus (de));
|
2009-09-17 07:32:36 +00:00
|
|
|
glxColorRGB(Style::Color(Style::DATUM));
|
2009-01-04 12:01:46 +00:00
|
|
|
}
|
|
|
|
|
2008-06-06 08:14:37 +00:00
|
|
|
glxVertex3v(v.Plus (r).Plus (d));
|
|
|
|
glxVertex3v(v.Plus (r).Minus(d));
|
|
|
|
glxVertex3v(v.Minus(r).Minus(d));
|
|
|
|
glxVertex3v(v.Minus(r).Plus (d));
|
|
|
|
}
|
|
|
|
glEnd();
|
2008-06-17 19:12:25 +00:00
|
|
|
glxDepthRangeOffset(0);
|
2008-06-06 08:14:37 +00:00
|
|
|
}
|
|
|
|
|
2009-04-19 05:53:16 +00:00
|
|
|
for(i = 0; i < SK.entity.n; i++) {
|
|
|
|
Entity *e = &(SK.entity.elem[i]);
|
2008-06-06 08:14:37 +00:00
|
|
|
if(e->IsPoint())
|
|
|
|
{
|
|
|
|
continue; // already handled
|
|
|
|
}
|
|
|
|
e->Draw();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Entity::Draw(void) {
|
2009-09-17 07:32:36 +00:00
|
|
|
hStyle hs = Style::ForEntity(h);
|
2009-09-18 08:14:15 +00:00
|
|
|
dogd.lineWidth = Style::Width(hs);
|
|
|
|
glLineWidth((float)dogd.lineWidth);
|
2009-09-17 07:32:36 +00:00
|
|
|
glxColorRGB(Style::Color(hs));
|
|
|
|
|
2008-06-06 08:14:37 +00:00
|
|
|
dogd.drawing = true;
|
|
|
|
DrawOrGetDistance();
|
|
|
|
}
|
|
|
|
|
2009-01-15 03:55:42 +00:00
|
|
|
void Entity::GenerateEdges(SEdgeList *el, bool includingConstruction) {
|
|
|
|
if(construction && !includingConstruction) return;
|
|
|
|
|
2009-01-19 03:51:00 +00:00
|
|
|
SBezierList sbl;
|
|
|
|
ZERO(&sbl);
|
|
|
|
GenerateBezierCurves(&sbl);
|
2009-01-15 03:55:42 +00:00
|
|
|
|
|
|
|
int i, j;
|
2009-01-19 03:51:00 +00:00
|
|
|
for(i = 0; i < sbl.l.n; i++) {
|
|
|
|
SBezier *sb = &(sbl.l.elem[i]);
|
2009-01-15 03:55:42 +00:00
|
|
|
|
|
|
|
List<Vector> lv;
|
|
|
|
ZERO(&lv);
|
2009-01-19 03:51:00 +00:00
|
|
|
sb->MakePwlInto(&lv);
|
2009-01-15 03:55:42 +00:00
|
|
|
for(j = 1; j < lv.n; j++) {
|
|
|
|
el->AddEdge(lv.elem[j-1], lv.elem[j]);
|
|
|
|
}
|
|
|
|
lv.Clear();
|
|
|
|
}
|
|
|
|
|
2009-01-19 03:51:00 +00:00
|
|
|
sbl.Clear();
|
2008-06-06 08:14:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
double Entity::GetDistance(Point2d mp) {
|
|
|
|
dogd.drawing = false;
|
|
|
|
dogd.mp = mp;
|
|
|
|
dogd.dmin = 1e12;
|
|
|
|
|
|
|
|
DrawOrGetDistance();
|
|
|
|
|
|
|
|
return dogd.dmin;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector Entity::GetReferencePos(void) {
|
|
|
|
dogd.drawing = false;
|
|
|
|
|
|
|
|
dogd.refp = SS.GW.offset.ScaledBy(-1);
|
|
|
|
DrawOrGetDistance();
|
|
|
|
|
|
|
|
return dogd.refp;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Entity::IsVisible(void) {
|
2009-04-19 05:53:16 +00:00
|
|
|
Group *g = SK.GetGroup(group);
|
2008-06-06 08:14:37 +00:00
|
|
|
|
|
|
|
if(g->h.v == Group::HGROUP_REFERENCES.v && IsNormal()) {
|
|
|
|
// The reference normals are always shown
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if(!g->visible) return false;
|
|
|
|
if(SS.GroupsInOrder(SS.GW.activeGroup, group)) return false;
|
|
|
|
|
2008-06-12 08:58:58 +00:00
|
|
|
// Don't check if points are hidden; this gets called only for
|
|
|
|
// selected or hovered points, and those should always be shown.
|
2008-06-06 08:14:37 +00:00
|
|
|
if(IsNormal() && !SS.GW.showNormals) return false;
|
|
|
|
|
2008-06-14 09:51:25 +00:00
|
|
|
if(!SS.GW.showWorkplanes) {
|
|
|
|
if(IsWorkplane() && !h.isFromRequest()) {
|
|
|
|
if(g->h.v != SS.GW.activeGroup.v) {
|
|
|
|
// The group-associated workplanes are hidden outside
|
|
|
|
// their group.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2008-06-06 08:14:37 +00:00
|
|
|
}
|
2008-06-13 04:41:27 +00:00
|
|
|
|
|
|
|
if(forceHidden) return false;
|
|
|
|
|
2008-06-06 08:14:37 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-04-20 07:30:09 +00:00
|
|
|
void Entity::CalculateNumerical(bool forExport) {
|
|
|
|
if(IsPoint()) actPoint = PointGetNum();
|
|
|
|
if(IsNormal()) actNormal = NormalGetNum();
|
|
|
|
if(type == DISTANCE || type == DISTANCE_N_COPY) {
|
|
|
|
actDistance = DistanceGetNum();
|
|
|
|
}
|
|
|
|
if(IsFace()) {
|
|
|
|
actPoint = FaceGetPointNum();
|
|
|
|
Vector n = FaceGetNormalNum();
|
|
|
|
actNormal = Quaternion::From(0, n.x, n.y, n.z);
|
|
|
|
}
|
|
|
|
if(forExport) {
|
|
|
|
// Visibility in copied import entities follows source file
|
|
|
|
actVisible = IsVisible();
|
|
|
|
} else {
|
|
|
|
// Copied entities within a file are always visible
|
|
|
|
actVisible = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Entity::PointIsFromReferences(void) {
|
|
|
|
return h.request().IsFromReferences();
|
|
|
|
}
|
|
|
|
|
2009-01-19 03:51:00 +00:00
|
|
|
void Entity::GenerateBezierCurves(SBezierList *sbl) {
|
|
|
|
SBezier sb;
|
2008-07-10 05:26:08 +00:00
|
|
|
|
2009-01-15 03:55:42 +00:00
|
|
|
switch(type) {
|
|
|
|
case LINE_SEGMENT: {
|
2009-04-19 05:53:16 +00:00
|
|
|
Vector a = SK.GetEntity(point[0])->PointGetNum();
|
|
|
|
Vector b = SK.GetEntity(point[1])->PointGetNum();
|
2009-01-19 03:51:00 +00:00
|
|
|
sb = SBezier::From(a, b);
|
|
|
|
sbl->l.Add(&sb);
|
2009-01-15 03:55:42 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CUBIC: {
|
2009-04-19 05:53:16 +00:00
|
|
|
Vector p0 = SK.GetEntity(point[0])->PointGetNum();
|
|
|
|
Vector p1 = SK.GetEntity(point[1])->PointGetNum();
|
|
|
|
Vector p2 = SK.GetEntity(point[2])->PointGetNum();
|
|
|
|
Vector p3 = SK.GetEntity(point[3])->PointGetNum();
|
2009-01-19 03:51:00 +00:00
|
|
|
sb = SBezier::From(p0, p1, p2, p3);
|
|
|
|
sbl->l.Add(&sb);
|
2009-01-15 03:55:42 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-07-10 05:26:08 +00:00
|
|
|
|
2009-01-15 03:55:42 +00:00
|
|
|
case CIRCLE:
|
|
|
|
case ARC_OF_CIRCLE: {
|
2009-04-19 05:53:16 +00:00
|
|
|
Vector center = SK.GetEntity(point[0])->PointGetNum();
|
|
|
|
Quaternion q = SK.GetEntity(normal)->NormalGetNum();
|
2009-01-15 03:55:42 +00:00
|
|
|
Vector u = q.RotationU(), v = q.RotationV();
|
|
|
|
double r = CircleGetRadiusNum();
|
|
|
|
double thetaa, thetab, dtheta;
|
|
|
|
|
2009-01-19 03:33:15 +00:00
|
|
|
if(r < LENGTH_EPS) {
|
|
|
|
// If a circle or an arc gets dragged through zero radius,
|
|
|
|
// then we just don't generate anything.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-01-15 03:55:42 +00:00
|
|
|
if(type == CIRCLE) {
|
|
|
|
thetaa = 0;
|
|
|
|
thetab = 2*PI;
|
|
|
|
dtheta = 2*PI;
|
|
|
|
} else {
|
|
|
|
ArcGetAngles(&thetaa, &thetab, &dtheta);
|
|
|
|
}
|
|
|
|
int i, n;
|
2009-06-21 09:02:36 +00:00
|
|
|
if(dtheta > (3*PI/2 + 0.01)) {
|
2009-01-15 03:55:42 +00:00
|
|
|
n = 4;
|
2009-06-21 09:02:36 +00:00
|
|
|
} else if(dtheta > (PI + 0.01)) {
|
2009-01-15 03:55:42 +00:00
|
|
|
n = 3;
|
2009-06-21 09:02:36 +00:00
|
|
|
} else if(dtheta > (PI/2 + 0.01)) {
|
2009-01-15 03:55:42 +00:00
|
|
|
n = 2;
|
|
|
|
} else {
|
|
|
|
n = 1;
|
|
|
|
}
|
|
|
|
dtheta /= n;
|
2008-07-10 05:26:08 +00:00
|
|
|
|
2009-01-15 03:55:42 +00:00
|
|
|
for(i = 0; i < n; i++) {
|
|
|
|
double s, c;
|
2008-07-10 05:26:08 +00:00
|
|
|
|
2009-01-15 03:55:42 +00:00
|
|
|
c = cos(thetaa);
|
|
|
|
s = sin(thetaa);
|
|
|
|
// The start point of the curve, and the tangent vector at
|
|
|
|
// that start point.
|
|
|
|
Vector p0 = center.Plus(u.ScaledBy( r*c)).Plus(v.ScaledBy(r*s)),
|
|
|
|
t0 = u.ScaledBy(-r*s). Plus(v.ScaledBy(r*c));
|
2008-07-10 05:26:08 +00:00
|
|
|
|
2009-01-15 03:55:42 +00:00
|
|
|
thetaa += dtheta;
|
2008-07-10 05:26:08 +00:00
|
|
|
|
2009-01-15 03:55:42 +00:00
|
|
|
c = cos(thetaa);
|
|
|
|
s = sin(thetaa);
|
|
|
|
Vector p2 = center.Plus(u.ScaledBy( r*c)).Plus(v.ScaledBy(r*s)),
|
|
|
|
t2 = u.ScaledBy(-r*s). Plus(v.ScaledBy(r*c));
|
|
|
|
|
|
|
|
// The control point must lie on both tangents.
|
|
|
|
Vector p1 = Vector::AtIntersectionOfLines(p0, p0.Plus(t0),
|
|
|
|
p2, p2.Plus(t2),
|
|
|
|
NULL);
|
|
|
|
|
2009-01-19 03:51:00 +00:00
|
|
|
SBezier sb = SBezier::From(p0, p1, p2);
|
|
|
|
sb.weight[1] = cos(dtheta/2);
|
|
|
|
sbl->l.Add(&sb);
|
2009-01-15 03:55:42 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case TTF_TEXT: {
|
2009-04-19 05:53:16 +00:00
|
|
|
Vector topLeft = SK.GetEntity(point[0])->PointGetNum();
|
|
|
|
Vector botLeft = SK.GetEntity(point[1])->PointGetNum();
|
2009-01-15 03:55:42 +00:00
|
|
|
Vector n = Normal()->NormalN();
|
|
|
|
Vector v = topLeft.Minus(botLeft);
|
|
|
|
Vector u = (v.Cross(n)).WithMagnitude(v.Magnitude());
|
|
|
|
|
2009-01-19 03:51:00 +00:00
|
|
|
SS.fonts.PlotString(font.str, str.str, 0, sbl, botLeft, u, v);
|
2009-01-15 03:55:42 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
// Not a problem, points and normals and such don't generate curves
|
|
|
|
break;
|
2008-07-10 05:26:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-30 09:09:17 +00:00
|
|
|
void Entity::DrawOrGetDistance(void) {
|
2009-01-15 03:55:42 +00:00
|
|
|
if(!IsVisible()) return;
|
2008-06-06 08:14:37 +00:00
|
|
|
|
2009-04-19 05:53:16 +00:00
|
|
|
Group *g = SK.GetGroup(group);
|
2008-06-06 08:14:37 +00:00
|
|
|
|
|
|
|
switch(type) {
|
|
|
|
case POINT_N_COPY:
|
|
|
|
case POINT_N_TRANS:
|
|
|
|
case POINT_N_ROT_TRANS:
|
|
|
|
case POINT_N_ROT_AA:
|
|
|
|
case POINT_IN_3D:
|
|
|
|
case POINT_IN_2D: {
|
|
|
|
Vector v = PointGetNum();
|
2008-06-06 09:14:25 +00:00
|
|
|
dogd.refp = v;
|
2008-06-06 08:14:37 +00:00
|
|
|
|
|
|
|
if(dogd.drawing) {
|
|
|
|
double s = 3.5;
|
|
|
|
Vector r = SS.GW.projRight.ScaledBy(s/SS.GW.scale);
|
|
|
|
Vector d = SS.GW.projUp.ScaledBy(s/SS.GW.scale);
|
|
|
|
|
2009-09-17 07:32:36 +00:00
|
|
|
glxColorRGB(Style::Color(Style::DATUM));
|
2008-06-17 19:12:25 +00:00
|
|
|
glxDepthRangeOffset(6);
|
2008-06-06 08:14:37 +00:00
|
|
|
glBegin(GL_QUADS);
|
|
|
|
glxVertex3v(v.Plus (r).Plus (d));
|
|
|
|
glxVertex3v(v.Plus (r).Minus(d));
|
|
|
|
glxVertex3v(v.Minus(r).Minus(d));
|
|
|
|
glxVertex3v(v.Minus(r).Plus (d));
|
|
|
|
glEnd();
|
2008-06-17 19:12:25 +00:00
|
|
|
glxDepthRangeOffset(0);
|
2008-06-06 08:14:37 +00:00
|
|
|
} else {
|
|
|
|
Point2d pp = SS.GW.ProjectPoint(v);
|
2008-06-11 04:22:52 +00:00
|
|
|
dogd.dmin = pp.DistanceTo(dogd.mp) - 6;
|
2008-06-06 08:14:37 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case NORMAL_N_COPY:
|
|
|
|
case NORMAL_N_ROT:
|
|
|
|
case NORMAL_N_ROT_AA:
|
|
|
|
case NORMAL_IN_3D:
|
|
|
|
case NORMAL_IN_2D: {
|
|
|
|
int i;
|
|
|
|
for(i = 0; i < 2; i++) {
|
2009-06-07 23:00:57 +00:00
|
|
|
if(i == 0 && !SS.GW.showNormals) {
|
|
|
|
// When the normals are hidden, we will continue to show
|
|
|
|
// the coordinate axes at the bottom left corner, but
|
|
|
|
// not at the origin.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2008-06-06 08:14:37 +00:00
|
|
|
hRequest hr = h.request();
|
2009-09-17 07:32:36 +00:00
|
|
|
// Always draw the x, y, and z axes in red, green, and blue;
|
|
|
|
// brighter for the ones at the bottom left of the screen,
|
|
|
|
// dimmer for the ones at the model origin.
|
|
|
|
int f = (i == 0 ? 100 : 255);
|
2008-06-06 08:14:37 +00:00
|
|
|
if(hr.v == Request::HREQUEST_REFERENCE_XY.v) {
|
2009-09-17 07:32:36 +00:00
|
|
|
glxColorRGB(RGB(0, 0, f));
|
2008-06-06 08:14:37 +00:00
|
|
|
} else if(hr.v == Request::HREQUEST_REFERENCE_YZ.v) {
|
2009-09-17 07:32:36 +00:00
|
|
|
glxColorRGB(RGB(f, 0, 0));
|
2008-06-06 08:14:37 +00:00
|
|
|
} else if(hr.v == Request::HREQUEST_REFERENCE_ZX.v) {
|
2009-09-17 07:32:36 +00:00
|
|
|
glxColorRGB(RGB(0, f, 0));
|
2008-06-06 08:14:37 +00:00
|
|
|
} else {
|
2009-09-17 07:32:36 +00:00
|
|
|
glxColorRGB(Style::Color(Style::NORMALS));
|
2008-06-06 08:14:37 +00:00
|
|
|
if(i > 0) break;
|
|
|
|
}
|
|
|
|
|
|
|
|
Quaternion q = NormalGetNum();
|
|
|
|
Vector tail;
|
|
|
|
if(i == 0) {
|
2009-04-19 05:53:16 +00:00
|
|
|
tail = SK.GetEntity(point[0])->PointGetNum();
|
2008-06-06 08:14:37 +00:00
|
|
|
glLineWidth(1);
|
|
|
|
} else {
|
|
|
|
// Draw an extra copy of the x, y, and z axes, that's
|
|
|
|
// always in the corner of the view and at the front.
|
|
|
|
// So those are always available, perhaps useful.
|
|
|
|
double s = SS.GW.scale;
|
|
|
|
double h = 60 - SS.GW.height/2;
|
|
|
|
double w = 60 - SS.GW.width/2;
|
|
|
|
tail = SS.GW.projRight.ScaledBy(w/s).Plus(
|
2008-06-17 19:12:25 +00:00
|
|
|
SS.GW.projUp. ScaledBy(h/s)).Minus(SS.GW.offset);
|
|
|
|
glxDepthRangeLockToFront(true);
|
2008-06-06 08:14:37 +00:00
|
|
|
glLineWidth(2);
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector v = (q.RotationN()).WithMagnitude(50/SS.GW.scale);
|
|
|
|
Vector tip = tail.Plus(v);
|
|
|
|
LineDrawOrGetDistance(tail, tip);
|
|
|
|
|
|
|
|
v = v.WithMagnitude(12/SS.GW.scale);
|
|
|
|
Vector axis = q.RotationV();
|
|
|
|
LineDrawOrGetDistance(tip,tip.Minus(v.RotatedAbout(axis, 0.6)));
|
|
|
|
LineDrawOrGetDistance(tip,tip.Minus(v.RotatedAbout(axis,-0.6)));
|
|
|
|
}
|
2008-06-17 19:12:25 +00:00
|
|
|
glxDepthRangeLockToFront(false);
|
2008-06-06 08:14:37 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case DISTANCE:
|
|
|
|
case DISTANCE_N_COPY:
|
|
|
|
// These are used only as data structures, nothing to display.
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WORKPLANE: {
|
|
|
|
Vector p;
|
2009-04-19 05:53:16 +00:00
|
|
|
p = SK.GetEntity(point[0])->PointGetNum();
|
2008-06-06 08:14:37 +00:00
|
|
|
|
|
|
|
Vector u = Normal()->NormalU();
|
|
|
|
Vector v = Normal()->NormalV();
|
|
|
|
|
|
|
|
double s = (min(SS.GW.width, SS.GW.height))*0.45/SS.GW.scale;
|
|
|
|
|
|
|
|
Vector us = u.ScaledBy(s);
|
|
|
|
Vector vs = v.ScaledBy(s);
|
|
|
|
|
|
|
|
Vector pp = p.Plus (us).Plus (vs);
|
|
|
|
Vector pm = p.Plus (us).Minus(vs);
|
|
|
|
Vector mm = p.Minus(us).Minus(vs), mm2 = mm;
|
|
|
|
Vector mp = p.Minus(us).Plus (vs);
|
|
|
|
|
|
|
|
glLineWidth(1);
|
2009-09-17 07:32:36 +00:00
|
|
|
glxColorRGB(Style::Color(Style::NORMALS));
|
2008-06-06 08:14:37 +00:00
|
|
|
glEnable(GL_LINE_STIPPLE);
|
|
|
|
glLineStipple(3, 0x1111);
|
|
|
|
if(!h.isFromRequest()) {
|
|
|
|
mm = mm.Plus(v.ScaledBy(60/SS.GW.scale));
|
|
|
|
mm2 = mm2.Plus(u.ScaledBy(60/SS.GW.scale));
|
|
|
|
LineDrawOrGetDistance(mm2, mm);
|
|
|
|
}
|
|
|
|
LineDrawOrGetDistance(pp, pm);
|
|
|
|
LineDrawOrGetDistance(pm, mm2);
|
|
|
|
LineDrawOrGetDistance(mm, mp);
|
|
|
|
LineDrawOrGetDistance(mp, pp);
|
|
|
|
glDisable(GL_LINE_STIPPLE);
|
|
|
|
|
|
|
|
char *str = DescriptionString()+5;
|
|
|
|
if(dogd.drawing) {
|
2009-07-03 20:55:57 +00:00
|
|
|
glxWriteText(str, mm2, u, v, NULL, NULL);
|
2008-06-06 08:14:37 +00:00
|
|
|
} else {
|
|
|
|
Vector pos = mm2.Plus(u.ScaledBy(glxStrWidth(str)/2)).Plus(
|
|
|
|
v.ScaledBy(glxStrHeight()/2));
|
|
|
|
Point2d pp = SS.GW.ProjectPoint(pos);
|
|
|
|
dogd.dmin = min(dogd.dmin, pp.DistanceTo(dogd.mp) - 10);
|
|
|
|
// If a line lies in a plane, then select the line, not
|
|
|
|
// the plane.
|
|
|
|
dogd.dmin += 3;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-01-15 03:55:42 +00:00
|
|
|
case LINE_SEGMENT:
|
|
|
|
case CIRCLE:
|
|
|
|
case ARC_OF_CIRCLE:
|
|
|
|
case CUBIC:
|
|
|
|
case TTF_TEXT:
|
|
|
|
// Nothing but the curve(s).
|
2008-06-06 08:14:37 +00:00
|
|
|
break;
|
2008-06-30 09:09:17 +00:00
|
|
|
|
2008-06-06 08:14:37 +00:00
|
|
|
case FACE_NORMAL_PT:
|
|
|
|
case FACE_XPROD:
|
|
|
|
case FACE_N_ROT_TRANS:
|
2008-06-21 22:49:57 +00:00
|
|
|
case FACE_N_TRANS:
|
|
|
|
case FACE_N_ROT_AA:
|
2008-06-06 08:14:37 +00:00
|
|
|
// Do nothing; these are drawn with the triangle mesh
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
oops();
|
|
|
|
}
|
2009-01-15 03:55:42 +00:00
|
|
|
|
|
|
|
// And draw the curves; generate the rational polynomial curves for
|
|
|
|
// everything, then piecewise linearize them, and display those.
|
|
|
|
SEdgeList sel;
|
|
|
|
ZERO(&sel);
|
|
|
|
GenerateEdges(&sel, true);
|
|
|
|
int i;
|
|
|
|
for(i = 0; i < sel.l.n; i++) {
|
|
|
|
SEdge *se = &(sel.l.elem[i]);
|
2009-09-18 08:14:15 +00:00
|
|
|
LineDrawOrGetDistance(se->a, se->b, true);
|
2009-01-15 03:55:42 +00:00
|
|
|
}
|
|
|
|
sel.Clear();
|
2008-06-06 08:14:37 +00:00
|
|
|
}
|
|
|
|
|