Add selectable faces, by associating an hEntity with the triangle's
metadata. And add point-on-face constraints to go with that. Still needs some cleanup for the user interface. [git-p4: depot-paths = "//depot/solvespace/": change = 1766]
This commit is contained in:
parent
57db9bea34
commit
6748160026
|
@ -126,6 +126,10 @@ void Constraint::MenuConstrain(int id) {
|
||||||
c.type = PT_ON_CIRCLE;
|
c.type = PT_ON_CIRCLE;
|
||||||
c.ptA = gs.point[0];
|
c.ptA = gs.point[0];
|
||||||
c.entityA = gs.entity[0];
|
c.entityA = gs.entity[0];
|
||||||
|
} else if(gs.points == 1 && gs.faces == 1 && gs.n == 2) {
|
||||||
|
c.type = PT_ON_FACE;
|
||||||
|
c.ptA = gs.point[0];
|
||||||
|
c.entityA = gs.face[0];
|
||||||
} else {
|
} else {
|
||||||
Error("Bad selection for on point / curve / plane constraint.");
|
Error("Bad selection for on point / curve / plane constraint.");
|
||||||
return;
|
return;
|
||||||
|
@ -547,6 +551,16 @@ void Constraint::Generate(IdList<Equation,hEquation> *l) {
|
||||||
SS.GetEntity(ptA)->PointGetExprs(), entityA), 0);
|
SS.GetEntity(ptA)->PointGetExprs(), entityA), 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PT_ON_FACE: {
|
||||||
|
// a plane, n dot (p - p0) = 0
|
||||||
|
ExprVector p = SS.GetEntity(ptA)->PointGetExprs();
|
||||||
|
Entity *f = SS.GetEntity(entityA);
|
||||||
|
ExprVector p0 = f->FaceGetPointExprs();
|
||||||
|
ExprVector n = f->FaceGetNormalExprs();
|
||||||
|
AddEq(l, (p.Minus(p0)).Dot(n), 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case PT_ON_LINE:
|
case PT_ON_LINE:
|
||||||
if(workplane.v == Entity::FREE_IN_3D.v) {
|
if(workplane.v == Entity::FREE_IN_3D.v) {
|
||||||
Entity *ln = SS.GetEntity(entityA);
|
Entity *ln = SS.GetEntity(entityA);
|
||||||
|
|
|
@ -224,11 +224,25 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
||||||
|
|
||||||
case PT_ON_CIRCLE:
|
case PT_ON_CIRCLE:
|
||||||
case PT_ON_LINE:
|
case PT_ON_LINE:
|
||||||
|
case PT_ON_FACE:
|
||||||
case PT_IN_PLANE: {
|
case PT_IN_PLANE: {
|
||||||
double s = 7/SS.GW.scale;
|
double s = 8/SS.GW.scale;
|
||||||
Vector p = SS.GetEntity(ptA)->PointGetNum();
|
Vector p = SS.GetEntity(ptA)->PointGetNum();
|
||||||
Vector r = gr.WithMagnitude(s);
|
Vector r, d;
|
||||||
Vector d = gu.WithMagnitude(s);
|
if(type == PT_ON_FACE) {
|
||||||
|
Vector n = SS.GetEntity(entityA)->FaceGetNormalNum();
|
||||||
|
r = n.Normal(0);
|
||||||
|
d = n.Normal(1);
|
||||||
|
} else if(type == PT_IN_PLANE) {
|
||||||
|
Entity *n = SS.GetEntity(entityA)->Normal();
|
||||||
|
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);
|
||||||
LineDrawOrGetDistance(p.Plus (r).Plus (d), p.Plus (r).Minus(d));
|
LineDrawOrGetDistance(p.Plus (r).Plus (d), p.Plus (r).Minus(d));
|
||||||
LineDrawOrGetDistance(p.Plus (r).Minus(d), p.Minus(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).Minus(d), p.Minus(r).Plus (d));
|
||||||
|
|
1
dsc.h
1
dsc.h
|
@ -16,6 +16,7 @@ public:
|
||||||
double w, vx, vy, vz;
|
double w, vx, vy, vz;
|
||||||
|
|
||||||
static Quaternion From(double w, double vx, double vy, double vz);
|
static Quaternion From(double w, double vx, double vy, double vz);
|
||||||
|
static Quaternion From(hParam w, hParam vx, hParam vy, hParam vz);
|
||||||
static Quaternion From(Vector u, Vector v);
|
static Quaternion From(Vector u, Vector v);
|
||||||
|
|
||||||
Quaternion Plus(Quaternion b);
|
Quaternion Plus(Quaternion b);
|
||||||
|
|
75
entity.cpp
75
entity.cpp
|
@ -574,6 +574,69 @@ Quaternion Entity::PointGetQuaternion(void) {
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Entity::IsFace(void) {
|
||||||
|
switch(type) {
|
||||||
|
case FACE_NORMAL_PT:
|
||||||
|
case FACE_XPROD:
|
||||||
|
case FACE_N_ROT_TRANS:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExprVector Entity::FaceGetNormalExprs(void) {
|
||||||
|
ExprVector r;
|
||||||
|
if(type == FACE_NORMAL_PT) {
|
||||||
|
r = ExprVector::From(numNormal.vx, numNormal.vy, numNormal.vz);
|
||||||
|
} else if(type == FACE_XPROD) {
|
||||||
|
ExprVector vc = ExprVector::From(param[0], param[1], param[2]);
|
||||||
|
ExprVector vn = ExprVector::From(numVector);
|
||||||
|
r = vc.Cross(vn);
|
||||||
|
} else if(type == FACE_N_ROT_TRANS) {
|
||||||
|
// The numerical normal vector gets the rotation
|
||||||
|
r = ExprVector::From(numNormal.vx, numNormal.vy, numNormal.vz);
|
||||||
|
ExprQuaternion q =
|
||||||
|
ExprQuaternion::From(param[3], param[4], param[5], param[6]);
|
||||||
|
r = q.Rotate(r);
|
||||||
|
} else oops();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector Entity::FaceGetNormalNum(void) {
|
||||||
|
Vector r;
|
||||||
|
if(type == FACE_NORMAL_PT) {
|
||||||
|
r = Vector::From(numNormal.vx, numNormal.vy, numNormal.vz);
|
||||||
|
} else if(type == FACE_XPROD) {
|
||||||
|
Vector vc = Vector::From(param[0], param[1], param[2]);
|
||||||
|
r = vc.Cross(numVector);
|
||||||
|
} else if(type == FACE_N_ROT_TRANS) {
|
||||||
|
// The numerical normal vector gets the rotation
|
||||||
|
r = Vector::From(numNormal.vx, numNormal.vy, numNormal.vz);
|
||||||
|
Quaternion q = Quaternion::From(param[3], param[4], param[5], param[6]);
|
||||||
|
r = q.Rotate(r);
|
||||||
|
} else oops();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExprVector Entity::FaceGetPointExprs(void) {
|
||||||
|
ExprVector r;
|
||||||
|
if(type == FACE_NORMAL_PT) {
|
||||||
|
r = SS.GetEntity(point[0])->PointGetExprs();
|
||||||
|
} else if(type == FACE_XPROD) {
|
||||||
|
r = ExprVector::From(numPoint);
|
||||||
|
} else if(type == FACE_N_ROT_TRANS) {
|
||||||
|
// The numerical point gets the rotation and translation.
|
||||||
|
ExprVector trans = ExprVector::From(param[0], param[1], param[2]);
|
||||||
|
ExprQuaternion q =
|
||||||
|
ExprQuaternion::From(param[3], param[4], param[5], param[6]);
|
||||||
|
r = ExprVector::From(numPoint);
|
||||||
|
r = q.Rotate(r);
|
||||||
|
r = r.Plus(trans);
|
||||||
|
} else oops();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
void Entity::LineDrawOrGetDistance(Vector a, Vector b) {
|
void Entity::LineDrawOrGetDistance(Vector a, Vector b) {
|
||||||
if(dogd.drawing) {
|
if(dogd.drawing) {
|
||||||
// glPolygonOffset works only on polys, not lines, so do it myself
|
// glPolygonOffset works only on polys, not lines, so do it myself
|
||||||
|
@ -890,6 +953,12 @@ void Entity::DrawOrGetDistance(int order) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case FACE_NORMAL_PT:
|
||||||
|
case FACE_XPROD:
|
||||||
|
case FACE_N_ROT_TRANS:
|
||||||
|
// Do nothing; these are drawn with the triangle mesh
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
oops();
|
oops();
|
||||||
}
|
}
|
||||||
|
@ -933,5 +1002,11 @@ void Entity::CalculateNumerical(void) {
|
||||||
if(type == DISTANCE || type == DISTANCE_N_COPY) {
|
if(type == DISTANCE || type == DISTANCE_N_COPY) {
|
||||||
actDistance = DistanceGetNum();
|
actDistance = DistanceGetNum();
|
||||||
}
|
}
|
||||||
|
if(IsFace()) {
|
||||||
|
ExprVector p = FaceGetPointExprs();
|
||||||
|
ExprVector n = FaceGetNormalExprs();
|
||||||
|
numPoint = Vector::From( p.x->Eval(), p.y->Eval(), p.z->Eval());
|
||||||
|
numNormal = Quaternion::From(0, n.x->Eval(), n.y->Eval(), n.z->Eval());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
17
expr.cpp
17
expr.cpp
|
@ -21,6 +21,14 @@ ExprVector ExprVector::From(hParam x, hParam y, hParam z) {
|
||||||
return ve;
|
return ve;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExprVector ExprVector::From(double x, double y, double z) {
|
||||||
|
ExprVector ve;
|
||||||
|
ve.x = Expr::From(x);
|
||||||
|
ve.y = Expr::From(y);
|
||||||
|
ve.z = Expr::From(z);
|
||||||
|
return ve;
|
||||||
|
}
|
||||||
|
|
||||||
ExprVector ExprVector::Minus(ExprVector b) {
|
ExprVector ExprVector::Minus(ExprVector b) {
|
||||||
ExprVector r;
|
ExprVector r;
|
||||||
r.x = x->Minus(b.x);
|
r.x = x->Minus(b.x);
|
||||||
|
@ -236,6 +244,15 @@ int Expr::Children(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Expr::Nodes(void) {
|
||||||
|
switch(Children()) {
|
||||||
|
case 0: return 1;
|
||||||
|
case 1: return 1 + a->Nodes();
|
||||||
|
case 2: return 1 + a->Nodes() + b->Nodes();
|
||||||
|
default: oops();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Expr *Expr::DeepCopy(void) {
|
Expr *Expr::DeepCopy(void) {
|
||||||
Expr *n = AllocExpr();
|
Expr *n = AllocExpr();
|
||||||
*n = *this;
|
*n = *this;
|
||||||
|
|
3
expr.h
3
expr.h
|
@ -92,6 +92,8 @@ public:
|
||||||
Expr *DeepCopy(void);
|
Expr *DeepCopy(void);
|
||||||
// number of child nodes: 0 (e.g. constant), 1 (sqrt), or 2 (+)
|
// number of child nodes: 0 (e.g. constant), 1 (sqrt), or 2 (+)
|
||||||
int Children(void);
|
int Children(void);
|
||||||
|
// total number of nodes in the tree
|
||||||
|
int Nodes(void);
|
||||||
|
|
||||||
// Make a copy, with the parameters (usually referenced by hParam)
|
// Make a copy, with the parameters (usually referenced by hParam)
|
||||||
// resolved to pointers to the actual value. This speeds things up
|
// resolved to pointers to the actual value. This speeds things up
|
||||||
|
@ -125,6 +127,7 @@ public:
|
||||||
static ExprVector From(Expr *x, Expr *y, Expr *z);
|
static ExprVector From(Expr *x, Expr *y, Expr *z);
|
||||||
static ExprVector From(Vector vn);
|
static ExprVector From(Vector vn);
|
||||||
static ExprVector From(hParam x, hParam y, hParam z);
|
static ExprVector From(hParam x, hParam y, hParam z);
|
||||||
|
static ExprVector From(double x, double y, double z);
|
||||||
|
|
||||||
ExprVector Plus(ExprVector b);
|
ExprVector Plus(ExprVector b);
|
||||||
ExprVector Minus(ExprVector b);
|
ExprVector Minus(ExprVector b);
|
||||||
|
|
17
glhelper.cpp
17
glhelper.cpp
|
@ -111,7 +111,7 @@ void glxColor4d(double r, double g, double b, double a)
|
||||||
if(!ColorLocked) glColor4d(r, g, b, a);
|
if(!ColorLocked) glColor4d(r, g, b, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
void glxFillMesh(bool useModelColor, SMesh *m)
|
void glxFillMesh(int specColor, SMesh *m, DWORD h, DWORD s1, DWORD s2)
|
||||||
{
|
{
|
||||||
glEnable(GL_NORMALIZE);
|
glEnable(GL_NORMALIZE);
|
||||||
int prevColor = -1;
|
int prevColor = -1;
|
||||||
|
@ -121,8 +121,19 @@ void glxFillMesh(bool useModelColor, SMesh *m)
|
||||||
Vector n = tr->Normal();
|
Vector n = tr->Normal();
|
||||||
glNormal3d(n.x, n.y, n.z);
|
glNormal3d(n.x, n.y, n.z);
|
||||||
|
|
||||||
int color = tr->meta.color;
|
int color;
|
||||||
if(useModelColor && color != prevColor) {
|
if((s1 != 0 && tr->meta.face == s1) ||
|
||||||
|
(s2 != 0 && tr->meta.face == s2))
|
||||||
|
{
|
||||||
|
color = RGB(200, 0, 0);
|
||||||
|
} else if(h != 0 && tr->meta.face == h) {
|
||||||
|
color = RGB(200, 200, 0);
|
||||||
|
} else if(specColor < 0) {
|
||||||
|
color = tr->meta.color;
|
||||||
|
} else {
|
||||||
|
color = specColor;
|
||||||
|
}
|
||||||
|
if(color != prevColor) {
|
||||||
GLfloat mpf[] = { ((color >> 0) & 0xff) / 255.0f,
|
GLfloat mpf[] = { ((color >> 0) & 0xff) / 255.0f,
|
||||||
((color >> 8) & 0xff) / 255.0f,
|
((color >> 8) & 0xff) / 255.0f,
|
||||||
((color >> 16) & 0xff) / 255.0f, 1.0 };
|
((color >> 16) & 0xff) / 255.0f, 1.0 };
|
||||||
|
|
|
@ -745,6 +745,15 @@ void GraphicsWindow::HitTestMakeSelection(Point2d mp) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Faces, from the triangle mesh; these are lowest priority
|
||||||
|
if(s.constraint.v == 0 && s.entity.v == 0 && (showMesh || showShaded)) {
|
||||||
|
SMesh *m = &((SS.GetGroup(activeGroup))->mesh);
|
||||||
|
DWORD v = m->FirstIntersectionWith(mp);
|
||||||
|
if(v) {
|
||||||
|
s.entity.v = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(!s.Equals(&hover)) {
|
if(!s.Equals(&hover)) {
|
||||||
hover = s;
|
hover = s;
|
||||||
InvalidateGraphics();
|
InvalidateGraphics();
|
||||||
|
@ -804,6 +813,11 @@ void GraphicsWindow::GroupSelection(void) {
|
||||||
gs.vector[(gs.vectors)++] = s->entity;
|
gs.vector[(gs.vectors)++] = s->entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Faces (which are special, associated/drawn with triangles)
|
||||||
|
if(e->IsFace()) {
|
||||||
|
gs.face[(gs.faces)++] = s->entity;
|
||||||
|
}
|
||||||
|
|
||||||
// And some aux counts too
|
// And some aux counts too
|
||||||
switch(e->type) {
|
switch(e->type) {
|
||||||
case Entity::WORKPLANE: (gs.workplanes)++; break;
|
case Entity::WORKPLANE: (gs.workplanes)++; break;
|
||||||
|
|
29
mesh.cpp
29
mesh.cpp
|
@ -235,6 +235,35 @@ void SMesh::MakeFromDifference(SMesh *a, SMesh *b) {
|
||||||
dbp("tris = %d", l.n);
|
dbp("tris = %d", l.n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DWORD SMesh::FirstIntersectionWith(Point2d mp) {
|
||||||
|
Vector gu = SS.GW.projRight, gv = SS.GW.projUp;
|
||||||
|
Vector gn = (gu.Cross(gv)).WithMagnitude(1);
|
||||||
|
|
||||||
|
Vector p0 = gu.ScaledBy(mp.x/SS.GW.scale).Plus(
|
||||||
|
gv.ScaledBy(mp.y/SS.GW.scale));
|
||||||
|
p0 = p0.Minus(SS.GW.offset);
|
||||||
|
|
||||||
|
double maxT = -1e12;
|
||||||
|
DWORD face = 0;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < l.n; i++) {
|
||||||
|
STriangle *tr = &(l.elem[i]);
|
||||||
|
Vector n = tr->Normal();
|
||||||
|
if(n.Dot(gn) < LENGTH_EPS) continue; // back-facing or on edge
|
||||||
|
|
||||||
|
if(tr->ContainsPointProjd(gn, p0)) {
|
||||||
|
// Let our line have the form r(t) = p0 + gn*t
|
||||||
|
double t = (n.Dot((tr->a).Minus(p0)))/(n.Dot(gn));
|
||||||
|
if(t > maxT) {
|
||||||
|
maxT = t;
|
||||||
|
face = tr->meta.face;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return face;
|
||||||
|
}
|
||||||
|
|
||||||
SBsp2 *SBsp2::Alloc(void) { return (SBsp2 *)AllocTemporary(sizeof(SBsp2)); }
|
SBsp2 *SBsp2::Alloc(void) { return (SBsp2 *)AllocTemporary(sizeof(SBsp2)); }
|
||||||
SBsp3 *SBsp3::Alloc(void) { return (SBsp3 *)AllocTemporary(sizeof(SBsp3)); }
|
SBsp3 *SBsp3::Alloc(void) { return (SBsp3 *)AllocTemporary(sizeof(SBsp3)); }
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,12 @@ Vector STriangle::Normal(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool STriangle::ContainsPoint(Vector p) {
|
bool STriangle::ContainsPoint(Vector p) {
|
||||||
|
Vector n = Normal();
|
||||||
|
return ContainsPointProjd(n.WithMagnitude(1), p);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool STriangle::ContainsPointProjd(Vector n, Vector p) {
|
||||||
Vector ab = b.Minus(a), bc = c.Minus(b), ca = a.Minus(c);
|
Vector ab = b.Minus(a), bc = c.Minus(b), ca = a.Minus(c);
|
||||||
Vector n = ab.Cross(bc);
|
|
||||||
n = n.WithMagnitude(1);
|
|
||||||
|
|
||||||
Vector no_ab = n.Cross(ab);
|
Vector no_ab = n.Cross(ab);
|
||||||
if(no_ab.Dot(p) < no_ab.Dot(a) - LENGTH_EPS) return false;
|
if(no_ab.Dot(p) < no_ab.Dot(a) - LENGTH_EPS) return false;
|
||||||
|
|
|
@ -114,6 +114,7 @@ public:
|
||||||
static STriangle From(STriMeta meta, Vector a, Vector b, Vector c);
|
static STriangle From(STriMeta meta, Vector a, Vector b, Vector c);
|
||||||
Vector Normal(void);
|
Vector Normal(void);
|
||||||
bool ContainsPoint(Vector p);
|
bool ContainsPoint(Vector p);
|
||||||
|
bool ContainsPointProjd(Vector n, Vector p);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SBsp2 {
|
class SBsp2 {
|
||||||
|
@ -190,6 +191,8 @@ public:
|
||||||
void AddAgainstBsp(SMesh *srcm, SBsp3 *bsp3);
|
void AddAgainstBsp(SMesh *srcm, SBsp3 *bsp3);
|
||||||
void MakeFromUnion(SMesh *a, SMesh *b);
|
void MakeFromUnion(SMesh *a, SMesh *b);
|
||||||
void MakeFromDifference(SMesh *a, SMesh *b);
|
void MakeFromDifference(SMesh *a, SMesh *b);
|
||||||
|
|
||||||
|
DWORD FirstIntersectionWith(Point2d mp);
|
||||||
};
|
};
|
||||||
|
|
||||||
// A linked list of triangles
|
// A linked list of triangles
|
||||||
|
|
125
sketch.cpp
125
sketch.cpp
|
@ -10,6 +10,8 @@ const hRequest Request::HREQUEST_REFERENCE_XY = { 1 };
|
||||||
const hRequest Request::HREQUEST_REFERENCE_YZ = { 2 };
|
const hRequest Request::HREQUEST_REFERENCE_YZ = { 2 };
|
||||||
const hRequest Request::HREQUEST_REFERENCE_ZX = { 3 };
|
const hRequest Request::HREQUEST_REFERENCE_ZX = { 3 };
|
||||||
|
|
||||||
|
#define gs (SS.GW.gs)
|
||||||
|
|
||||||
void Group::AddParam(IdList<Param,hParam> *param, hParam hp, double v) {
|
void Group::AddParam(IdList<Param,hParam> *param, hParam hp, double v) {
|
||||||
Param pa;
|
Param pa;
|
||||||
memset(&pa, 0, sizeof(pa));
|
memset(&pa, 0, sizeof(pa));
|
||||||
|
@ -30,7 +32,6 @@ void Group::MenuGroup(int id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
SS.GW.GroupSelection();
|
SS.GW.GroupSelection();
|
||||||
#define gs (SS.GW.gs)
|
|
||||||
|
|
||||||
switch(id) {
|
switch(id) {
|
||||||
case GraphicsWindow::MNU_GROUP_3D:
|
case GraphicsWindow::MNU_GROUP_3D:
|
||||||
|
@ -214,7 +215,7 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case EXTRUDE:
|
case EXTRUDE: {
|
||||||
AddParam(param, h.param(0), gn.x);
|
AddParam(param, h.param(0), gn.x);
|
||||||
AddParam(param, h.param(1), gn.y);
|
AddParam(param, h.param(1), gn.y);
|
||||||
AddParam(param, h.param(2), gn.z);
|
AddParam(param, h.param(2), gn.z);
|
||||||
|
@ -224,10 +225,16 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
|
||||||
} else if(subtype == TWO_SIDED) {
|
} else if(subtype == TWO_SIDED) {
|
||||||
ai = -1; af = 1;
|
ai = -1; af = 1;
|
||||||
} else oops();
|
} else oops();
|
||||||
|
|
||||||
|
// Get some arbitrary point in the sketch, that will be used
|
||||||
|
// as a reference when defining top and bottom faces.
|
||||||
|
hEntity pt = { 0 };
|
||||||
for(i = 0; i < entity->n; i++) {
|
for(i = 0; i < entity->n; i++) {
|
||||||
Entity *e = &(entity->elem[i]);
|
Entity *e = &(entity->elem[i]);
|
||||||
if(e->group.v != opA.v) continue;
|
if(e->group.v != opA.v) continue;
|
||||||
|
|
||||||
|
if(e->IsPoint()) pt = e->h;
|
||||||
|
|
||||||
e->CalculateNumerical();
|
e->CalculateNumerical();
|
||||||
hEntity he = e->h; e = NULL;
|
hEntity he = e->h; e = NULL;
|
||||||
// As soon as I call CopyEntity, e may become invalid! That
|
// As soon as I call CopyEntity, e may become invalid! That
|
||||||
|
@ -242,7 +249,11 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
|
||||||
true, false);
|
true, false);
|
||||||
MakeExtrusionLines(he);
|
MakeExtrusionLines(he);
|
||||||
}
|
}
|
||||||
|
// Remapped versions of that arbitrary point will be used to
|
||||||
|
// provide points on the plane faces.
|
||||||
|
MakeExtrusionTopBottomFaces(pt);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case TRANSLATE: {
|
case TRANSLATE: {
|
||||||
// The translation vector
|
// The translation vector
|
||||||
|
@ -386,16 +397,54 @@ hEntity Group::Remap(hEntity in, int copyNumber) {
|
||||||
|
|
||||||
void Group::MakeExtrusionLines(hEntity in) {
|
void Group::MakeExtrusionLines(hEntity in) {
|
||||||
Entity *ep = SS.GetEntity(in);
|
Entity *ep = SS.GetEntity(in);
|
||||||
if(!(ep->IsPoint())) return;
|
|
||||||
|
|
||||||
Entity en;
|
Entity en;
|
||||||
memset(&en, 0, sizeof(en));
|
ZERO(&en);
|
||||||
en.point[0] = Remap(ep->h, REMAP_TOP);
|
if(ep->IsPoint()) {
|
||||||
en.point[1] = Remap(ep->h, REMAP_BOTTOM);
|
// A point gets extruded to form a line segment
|
||||||
|
en.point[0] = Remap(ep->h, REMAP_TOP);
|
||||||
|
en.point[1] = Remap(ep->h, REMAP_BOTTOM);
|
||||||
|
en.group = h;
|
||||||
|
en.h = Remap(ep->h, REMAP_PT_TO_LINE);
|
||||||
|
en.type = Entity::LINE_SEGMENT;
|
||||||
|
SS.entity.Add(&en);
|
||||||
|
} else if(ep->type == Entity::LINE_SEGMENT) {
|
||||||
|
// A line gets extruded to form a plane face; an endpoint of the
|
||||||
|
// original line is a point in the plane, and the line is in the plane.
|
||||||
|
Vector a = SS.GetEntity(ep->point[0])->PointGetNum();
|
||||||
|
Vector b = SS.GetEntity(ep->point[1])->PointGetNum();
|
||||||
|
Vector ab = b.Minus(a);
|
||||||
|
|
||||||
|
en.param[0] = h.param(0);
|
||||||
|
en.param[1] = h.param(1);
|
||||||
|
en.param[2] = h.param(2);
|
||||||
|
en.numPoint = a;
|
||||||
|
en.numVector = ab;
|
||||||
|
|
||||||
|
en.group = h;
|
||||||
|
en.h = Remap(ep->h, REMAP_LINE_TO_FACE);
|
||||||
|
en.type = Entity::FACE_XPROD;
|
||||||
|
SS.entity.Add(&en);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Group::MakeExtrusionTopBottomFaces(hEntity pt) {
|
||||||
|
if(pt.v == 0) return;
|
||||||
|
Group *src = SS.GetGroup(opA);
|
||||||
|
Vector n = src->poly.normal;
|
||||||
|
|
||||||
|
Entity en;
|
||||||
|
ZERO(&en);
|
||||||
|
en.type = Entity::FACE_NORMAL_PT;
|
||||||
en.group = h;
|
en.group = h;
|
||||||
en.h = Remap(ep->h, 10);
|
|
||||||
en.type = Entity::LINE_SEGMENT;
|
en.numNormal = Quaternion::From(0, n.x, n.y, n.z);
|
||||||
// And then this line segment gets added
|
en.point[0] = Remap(pt, REMAP_TOP);
|
||||||
|
en.h = Remap(Entity::NO_ENTITY, REMAP_TOP);
|
||||||
|
SS.entity.Add(&en);
|
||||||
|
|
||||||
|
en.point[0] = Remap(pt, REMAP_BOTTOM);
|
||||||
|
en.h = Remap(Entity::NO_ENTITY, REMAP_BOTTOM);
|
||||||
SS.entity.Add(&en);
|
SS.entity.Add(&en);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -498,6 +547,23 @@ void Group::CopyEntity(Entity *ep, int timesApplied, int remap,
|
||||||
en.numDistance = ep->actDistance;
|
en.numDistance = ep->actDistance;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Entity::FACE_NORMAL_PT:
|
||||||
|
case Entity::FACE_XPROD:
|
||||||
|
case Entity::FACE_N_ROT_TRANS:
|
||||||
|
if(asTrans || asAxisAngle) return;
|
||||||
|
|
||||||
|
en.type = Entity::FACE_N_ROT_TRANS;
|
||||||
|
en.param[0] = dx;
|
||||||
|
en.param[1] = dy;
|
||||||
|
en.param[2] = dz;
|
||||||
|
en.param[3] = qw;
|
||||||
|
en.param[4] = qvx;
|
||||||
|
en.param[5] = qvy;
|
||||||
|
en.param[6] = qvz;
|
||||||
|
en.numPoint = ep->numPoint;
|
||||||
|
en.numNormal = ep->numNormal;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
oops();
|
oops();
|
||||||
}
|
}
|
||||||
|
@ -526,8 +592,8 @@ void Group::TagEdgesFromLineSegments(SEdgeList *el) {
|
||||||
|
|
||||||
for(j = 0; j < el->l.n; j++) {
|
for(j = 0; j < el->l.n; j++) {
|
||||||
SEdge *se = &(el->l.elem[j]);
|
SEdge *se = &(el->l.elem[j]);
|
||||||
if((p0.Equals(se->a) && p1.Equals(se->b))) se->tag = 1;
|
if((p0.Equals(se->a) && p1.Equals(se->b))) se->tag = e->h.v;
|
||||||
if((p0.Equals(se->b) && p1.Equals(se->a))) se->tag = 1;
|
if((p0.Equals(se->b) && p1.Equals(se->a))) se->tag = e->h.v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -583,6 +649,7 @@ void Group::MakePolygons(void) {
|
||||||
STriMeta meta = { 0, color };
|
STriMeta meta = { 0, color };
|
||||||
|
|
||||||
// Do the bottom; that has normal pointing opposite from translate
|
// Do the bottom; that has normal pointing opposite from translate
|
||||||
|
meta.face = Remap(Entity::NO_ENTITY, REMAP_BOTTOM).v;
|
||||||
for(i = 0; i < srcm.l.n; i++) {
|
for(i = 0; i < srcm.l.n; i++) {
|
||||||
STriangle *st = &(srcm.l.elem[i]);
|
STriangle *st = &(srcm.l.elem[i]);
|
||||||
Vector at = (st->a).Plus(tbot),
|
Vector at = (st->a).Plus(tbot),
|
||||||
|
@ -595,6 +662,7 @@ void Group::MakePolygons(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// And the top; that has the normal pointing the same dir as translate
|
// And the top; that has the normal pointing the same dir as translate
|
||||||
|
meta.face = Remap(Entity::NO_ENTITY, REMAP_TOP).v;
|
||||||
for(i = 0; i < srcm.l.n; i++) {
|
for(i = 0; i < srcm.l.n; i++) {
|
||||||
STriangle *st = &(srcm.l.elem[i]);
|
STriangle *st = &(srcm.l.elem[i]);
|
||||||
Vector at = (st->a).Plus(ttop),
|
Vector at = (st->a).Plus(ttop),
|
||||||
|
@ -618,6 +686,15 @@ void Group::MakePolygons(void) {
|
||||||
SEdge *edge = &(edges.l.elem[i]);
|
SEdge *edge = &(edges.l.elem[i]);
|
||||||
Vector abot = (edge->a).Plus(tbot), bbot = (edge->b).Plus(tbot);
|
Vector abot = (edge->a).Plus(tbot), bbot = (edge->b).Plus(tbot);
|
||||||
Vector atop = (edge->a).Plus(ttop), btop = (edge->b).Plus(ttop);
|
Vector atop = (edge->a).Plus(ttop), btop = (edge->b).Plus(ttop);
|
||||||
|
// We tagged the edges that came from line segments; their
|
||||||
|
// triangles should be associated with that plane face.
|
||||||
|
if(edge->tag) {
|
||||||
|
hEntity hl = { edge->tag };
|
||||||
|
hEntity hf = Remap(hl, REMAP_LINE_TO_FACE);
|
||||||
|
meta.face = hf.v;
|
||||||
|
} else {
|
||||||
|
meta.face = 0;
|
||||||
|
}
|
||||||
if(flipBottom) {
|
if(flipBottom) {
|
||||||
outm.AddTriangle(meta, bbot, abot, atop);
|
outm.AddTriangle(meta, bbot, abot, atop);
|
||||||
outm.AddTriangle(meta, bbot, atop, btop);
|
outm.AddTriangle(meta, bbot, atop, btop);
|
||||||
|
@ -641,6 +718,11 @@ void Group::MakePolygons(void) {
|
||||||
|
|
||||||
for(int i = 0; i < impMesh.l.n; i++) {
|
for(int i = 0; i < impMesh.l.n; i++) {
|
||||||
STriangle st = impMesh.l.elem[i];
|
STriangle st = impMesh.l.elem[i];
|
||||||
|
|
||||||
|
if(st.meta.face != 0) {
|
||||||
|
hEntity he = { st.meta.face };
|
||||||
|
st.meta.face = Remap(he, 0).v;
|
||||||
|
}
|
||||||
st.a = q.Rotate(st.a).Plus(offset);
|
st.a = q.Rotate(st.a).Plus(offset);
|
||||||
st.b = q.Rotate(st.b).Plus(offset);
|
st.b = q.Rotate(st.b).Plus(offset);
|
||||||
st.c = q.Rotate(st.c).Plus(offset);
|
st.c = q.Rotate(st.c).Plus(offset);
|
||||||
|
@ -665,21 +747,30 @@ void Group::Draw(void) {
|
||||||
// Show this even if the group is not visible. It's already possible
|
// Show this even if the group is not visible. It's already possible
|
||||||
// to show or hide just this with the "show solids" flag.
|
// to show or hide just this with the "show solids" flag.
|
||||||
|
|
||||||
bool useModelColor;
|
int specColor;
|
||||||
if(type != EXTRUDE && type != IMPORTED) {
|
if(type != EXTRUDE && type != IMPORTED) {
|
||||||
GLfloat mpf[] = { 0.1f, 0.1f, 0.1f, 1.0 };
|
specColor = RGB(25, 25, 25); // force the color to something dim
|
||||||
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mpf);
|
|
||||||
useModelColor = false;
|
|
||||||
} else {
|
} else {
|
||||||
useModelColor = true;
|
specColor = -1; // use the model color
|
||||||
}
|
}
|
||||||
// The back faces are drawn in red; should never seem them, since we
|
// The back faces are drawn in red; should never seem them, since we
|
||||||
// draw closed shells, so that's a debugging aid.
|
// draw closed shells, so that's a debugging aid.
|
||||||
GLfloat mpb[] = { 1.0f, 0.1f, 0.1f, 1.0 };
|
GLfloat mpb[] = { 1.0f, 0.1f, 0.1f, 1.0 };
|
||||||
glMaterialfv(GL_BACK, GL_AMBIENT_AND_DIFFUSE, mpb);
|
glMaterialfv(GL_BACK, GL_AMBIENT_AND_DIFFUSE, mpb);
|
||||||
|
|
||||||
|
// When we fill the mesh, we need to know which triangles are selected
|
||||||
|
// or hovered, in order to draw them differently.
|
||||||
|
DWORD mh = 0, ms1 = 0, ms2 = 0;
|
||||||
|
hEntity he = SS.GW.hover.entity;
|
||||||
|
if(he.v != 0 && SS.GetEntity(he)->IsFace()) {
|
||||||
|
mh = he.v;
|
||||||
|
}
|
||||||
|
SS.GW.GroupSelection();
|
||||||
|
if(gs.faces > 0) ms1 = gs.face[0].v;
|
||||||
|
if(gs.faces > 1) ms2 = gs.face[1].v;
|
||||||
|
|
||||||
glEnable(GL_LIGHTING);
|
glEnable(GL_LIGHTING);
|
||||||
if(SS.GW.showShaded) glxFillMesh(useModelColor, &mesh);
|
if(SS.GW.showShaded) glxFillMesh(specColor, &mesh, mh, ms1, ms2);
|
||||||
glDisable(GL_LIGHTING);
|
glDisable(GL_LIGHTING);
|
||||||
|
|
||||||
if(SS.GW.showMesh) glxDebugMesh(&mesh);
|
if(SS.GW.showMesh) glxDebugMesh(&mesh);
|
||||||
|
|
16
sketch.h
16
sketch.h
|
@ -148,8 +148,11 @@ public:
|
||||||
static const int REMAP_LAST = 1000;
|
static const int REMAP_LAST = 1000;
|
||||||
static const int REMAP_TOP = 1001;
|
static const int REMAP_TOP = 1001;
|
||||||
static const int REMAP_BOTTOM = 1002;
|
static const int REMAP_BOTTOM = 1002;
|
||||||
|
static const int REMAP_PT_TO_LINE = 1003;
|
||||||
|
static const int REMAP_LINE_TO_FACE = 1004;
|
||||||
hEntity Remap(hEntity in, int copyNumber);
|
hEntity Remap(hEntity in, int copyNumber);
|
||||||
void MakeExtrusionLines(hEntity in);
|
void MakeExtrusionLines(hEntity in);
|
||||||
|
void MakeExtrusionTopBottomFaces(hEntity pt);
|
||||||
void TagEdgesFromLineSegments(SEdgeList *sle);
|
void TagEdgesFromLineSegments(SEdgeList *sle);
|
||||||
void CopyEntity(Entity *ep, int timesApplied, int remap,
|
void CopyEntity(Entity *ep, int timesApplied, int remap,
|
||||||
hParam dx, hParam dy, hParam dz,
|
hParam dx, hParam dy, hParam dz,
|
||||||
|
@ -232,9 +235,9 @@ public:
|
||||||
static const int DISTANCE = 4000;
|
static const int DISTANCE = 4000;
|
||||||
static const int DISTANCE_N_COPY = 4001;
|
static const int DISTANCE_N_COPY = 4001;
|
||||||
|
|
||||||
static const int FACE_N_COPY = 5000;
|
static const int FACE_NORMAL_PT = 5000;
|
||||||
static const int FACE_N_TRANS = 5001;
|
static const int FACE_XPROD = 5001;
|
||||||
static const int FACE_N_XPROD = 5002;
|
static const int FACE_N_ROT_TRANS = 5002;
|
||||||
|
|
||||||
|
|
||||||
static const int WORKPLANE = 10000;
|
static const int WORKPLANE = 10000;
|
||||||
|
@ -258,6 +261,8 @@ public:
|
||||||
Vector numPoint;
|
Vector numPoint;
|
||||||
Quaternion numNormal;
|
Quaternion numNormal;
|
||||||
double numDistance;
|
double numDistance;
|
||||||
|
// and a bit more state that the faces need
|
||||||
|
Vector numVector;
|
||||||
|
|
||||||
// All points/normals/distances have their numerical value; this is
|
// All points/normals/distances have their numerical value; this is
|
||||||
// a convenience, to simplify the import/assembly code, so that the
|
// a convenience, to simplify the import/assembly code, so that the
|
||||||
|
@ -297,6 +302,11 @@ public:
|
||||||
Vector WorkplaneGetOffset(void);
|
Vector WorkplaneGetOffset(void);
|
||||||
Entity *Normal(void);
|
Entity *Normal(void);
|
||||||
|
|
||||||
|
bool IsFace(void);
|
||||||
|
ExprVector FaceGetNormalExprs(void);
|
||||||
|
Vector FaceGetNormalNum(void);
|
||||||
|
ExprVector FaceGetPointExprs(void);
|
||||||
|
|
||||||
bool IsPoint(void);
|
bool IsPoint(void);
|
||||||
// Applies for any of the point types
|
// Applies for any of the point types
|
||||||
Vector PointGetNum(void);
|
Vector PointGetNum(void);
|
||||||
|
|
|
@ -104,7 +104,7 @@ void glxVertex3v(Vector u);
|
||||||
typedef void GLX_CALLBACK glxCallbackFptr(void);
|
typedef void GLX_CALLBACK glxCallbackFptr(void);
|
||||||
void glxTesselatePolygon(GLUtesselator *gt, SPolygon *p);
|
void glxTesselatePolygon(GLUtesselator *gt, SPolygon *p);
|
||||||
void glxFillPolygon(SPolygon *p);
|
void glxFillPolygon(SPolygon *p);
|
||||||
void glxFillMesh(bool useModelColor, SMesh *m);
|
void glxFillMesh(int color, SMesh *m, DWORD h, DWORD s1, DWORD s2);
|
||||||
void glxDebugPolygon(SPolygon *p);
|
void glxDebugPolygon(SPolygon *p);
|
||||||
void glxDebugEdgeList(SEdgeList *l);
|
void glxDebugEdgeList(SEdgeList *l);
|
||||||
void glxDebugMesh(SMesh *m);
|
void glxDebugMesh(SMesh *m);
|
||||||
|
|
9
util.cpp
9
util.cpp
|
@ -32,6 +32,15 @@ Quaternion Quaternion::From(double w, double vx, double vy, double vz) {
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Quaternion Quaternion::From(hParam w, hParam vx, hParam vy, hParam vz) {
|
||||||
|
Quaternion q;
|
||||||
|
q.w = SS.GetParam(w )->val;
|
||||||
|
q.vx = SS.GetParam(vx)->val;
|
||||||
|
q.vy = SS.GetParam(vy)->val;
|
||||||
|
q.vz = SS.GetParam(vz)->val;
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
Quaternion Quaternion::From(Vector u, Vector v)
|
Quaternion Quaternion::From(Vector u, Vector v)
|
||||||
{
|
{
|
||||||
Vector n = u.Cross(v);
|
Vector n = u.Cross(v);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user