diff --git a/drawentity.cpp b/drawentity.cpp index a360719a..f39ced92 100644 --- a/drawentity.cpp +++ b/drawentity.cpp @@ -364,6 +364,8 @@ void Entity::DrawOrGetDistance(void) { case FACE_NORMAL_PT: case FACE_XPROD: case FACE_N_ROT_TRANS: + case FACE_N_TRANS: + case FACE_N_ROT_AA: // Do nothing; these are drawn with the triangle mesh break; diff --git a/entity.cpp b/entity.cpp index 0c4d087e..295d8c72 100644 --- a/entity.cpp +++ b/entity.cpp @@ -225,12 +225,7 @@ Quaternion Entity::NormalGetNum(void) { break; case NORMAL_N_ROT_AA: { - double theta = timesApplied*SS.GetParam(param[0])->val; - double s = sin(theta), c = cos(theta); - q.w = c; - q.vx = s*SS.GetParam(param[1])->val; - q.vy = s*SS.GetParam(param[2])->val; - q.vz = s*SS.GetParam(param[3])->val; + q = GetAxisAngleQuaternion(0); q = q.Times(numNormal); break; } @@ -318,15 +313,7 @@ ExprQuaternion Entity::NormalGetExprs(void) { case NORMAL_N_ROT_AA: { ExprQuaternion orig = ExprQuaternion::From(numNormal); - - Expr *theta = Expr::From(timesApplied)->Times( - Expr::From(param[0])); - Expr *c = theta->Cos(), *s = theta->Sin(); - q.w = c; - q.vx = s->Times(Expr::From(param[1])); - q.vy = s->Times(Expr::From(param[2])); - q.vz = s->Times(Expr::From(param[3])); - + q = GetAxisAngleQuaternionExprs(0); q = q.Times(orig); break; } @@ -486,14 +473,7 @@ ExprVector Entity::PointGetExprs(void) { case POINT_N_ROT_AA: { ExprVector orig = ExprVector::From(numPoint); ExprVector trans = ExprVector::From(param[0], param[1], param[2]); - Expr *theta = Expr::From(timesApplied)->Times( - Expr::From(param[3])); - Expr *c = theta->Cos(), *s = theta->Sin(); - ExprQuaternion q = { - c, - s->Times(Expr::From(param[4])), - s->Times(Expr::From(param[5])), - s->Times(Expr::From(param[6])) }; + ExprQuaternion q = GetAxisAngleQuaternionExprs(3); orig = orig.Minus(trans); orig = q.Rotate(orig); r = orig.Plus(trans); @@ -539,16 +519,35 @@ void Entity::PointForceQuaternionTo(Quaternion q) { SS.GetParam(param[6])->val = q.vz; } +Quaternion Entity::GetAxisAngleQuaternion(int param0) { + Quaternion q; + double theta = timesApplied*SS.GetParam(param[param0+0])->val; + double s = sin(theta), c = cos(theta); + q.w = c; + q.vx = s*SS.GetParam(param[param0+1])->val; + q.vy = s*SS.GetParam(param[param0+2])->val; + q.vz = s*SS.GetParam(param[param0+3])->val; + return q; +} + +ExprQuaternion Entity::GetAxisAngleQuaternionExprs(int param0) { + ExprQuaternion q; + + Expr *theta = Expr::From(timesApplied)->Times( + Expr::From(param[param0+0])); + Expr *c = theta->Cos(), *s = theta->Sin(); + q.w = c; + q.vx = s->Times(Expr::From(param[param0+1])); + q.vy = s->Times(Expr::From(param[param0+2])); + q.vz = s->Times(Expr::From(param[param0+3])); + return q; +} + Quaternion Entity::PointGetQuaternion(void) { Quaternion q; if(type == POINT_N_ROT_AA) { - double theta = timesApplied*SS.GetParam(param[3])->val; - double s = sin(theta), c = cos(theta); - q.w = c; - q.vx = s*SS.GetParam(param[4])->val; - q.vy = s*SS.GetParam(param[5])->val; - q.vz = s*SS.GetParam(param[6])->val; + q = GetAxisAngleQuaternion(3); } else if(type == POINT_N_ROT_TRANS) { q = Quaternion::From(param[3], param[4], param[5], param[6]); } else oops(); @@ -561,6 +560,8 @@ bool Entity::IsFace(void) { case FACE_NORMAL_PT: case FACE_XPROD: case FACE_N_ROT_TRANS: + case FACE_N_TRANS: + case FACE_N_ROT_AA: return true; default: return false; @@ -586,6 +587,12 @@ ExprVector Entity::FaceGetNormalExprs(void) { ExprQuaternion q = ExprQuaternion::From(param[3], param[4], param[5], param[6]); r = q.Rotate(r); + } else if(type == FACE_N_TRANS) { + r = ExprVector::From(numNormal.vx, numNormal.vy, numNormal.vz); + } else if(type == FACE_N_ROT_AA) { + r = ExprVector::From(numNormal.vx, numNormal.vy, numNormal.vz); + ExprQuaternion q = GetAxisAngleQuaternionExprs(3); + r = q.Rotate(r); } else oops(); return r; } @@ -603,6 +610,12 @@ Vector Entity::FaceGetNormalNum(void) { 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 if(type == FACE_N_TRANS) { + r = Vector::From(numNormal.vx, numNormal.vy, numNormal.vz); + } else if(type == FACE_N_ROT_AA) { + r = Vector::From(numNormal.vx, numNormal.vy, numNormal.vz); + Quaternion q = GetAxisAngleQuaternion(3); + r = q.Rotate(r); } else oops(); return r.WithMagnitude(1); } @@ -621,6 +634,17 @@ ExprVector Entity::FaceGetPointExprs(void) { r = ExprVector::From(numPoint); r = q.Rotate(r); r = r.Plus(trans); + } else if(type == FACE_N_TRANS) { + ExprVector trans = ExprVector::From(param[0], param[1], param[2]); + r = ExprVector::From(numPoint); + r = r.Plus(trans.ScaledBy(Expr::From(timesApplied))); + } else if(type == FACE_N_ROT_AA) { + ExprVector trans = ExprVector::From(param[0], param[1], param[2]); + ExprQuaternion q = GetAxisAngleQuaternionExprs(3); + r = ExprVector::From(numPoint); + r = r.Minus(trans); + r = q.Rotate(r); + r = r.Plus(trans); } else oops(); return r; } @@ -637,6 +661,15 @@ Vector Entity::FaceGetPointNum(void) { Quaternion q = Quaternion::From(param[3], param[4], param[5], param[6]); r = q.Rotate(numPoint); r = r.Plus(trans); + } else if(type == FACE_N_TRANS) { + Vector trans = Vector::From(param[0], param[1], param[2]); + r = numPoint.Plus(trans.ScaledBy(timesApplied)); + } else if(type == FACE_N_ROT_AA) { + Vector trans = Vector::From(param[0], param[1], param[2]); + Quaternion q = GetAxisAngleQuaternion(3); + r = numPoint.Minus(trans); + r = q.Rotate(r); + r = r.Plus(trans); } else oops(); return r; } diff --git a/group.cpp b/group.cpp index e82a54ff..11a8369b 100644 --- a/group.cpp +++ b/group.cpp @@ -642,16 +642,27 @@ void Group::CopyEntity(IdList *el, 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; + case Entity::FACE_N_TRANS: + case Entity::FACE_N_ROT_AA: + if(asTrans) { + en.type = Entity::FACE_N_TRANS; + en.param[0] = dx; + en.param[1] = dy; + en.param[2] = dz; + } else { + if(asAxisAngle) { + en.type = Entity::FACE_N_ROT_AA; + } else { + 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->actPoint; en.numNormal = ep->actNormal; break; diff --git a/groupmesh.cpp b/groupmesh.cpp index bf079509..85eaf9bd 100644 --- a/groupmesh.cpp +++ b/groupmesh.cpp @@ -126,6 +126,77 @@ void Group::AddQuadWithNormal(STriMeta meta, Vector out, if(n2.Magnitude() > LENGTH_EPS) thisMesh.AddTriangle(&quad2); } +void Group::GenerateMeshForStepAndRepeat(void) { + Group *src = SS.GetGroup(opA); + SMesh *srcm = &(src->thisMesh); // the mesh to step and repeat + + if(srcm->l.n == 0) { + runningMesh.Clear(); + runningMesh.MakeFromCopy(PreviousGroupMesh()); + return; + } + + SMesh origm; + ZERO(&origm); + origm.MakeFromCopy(src->PreviousGroupMesh()); + + int n = (int)valA, a0 = 0; + if(subtype == ONE_SIDED && skipFirst) { + a0++; n++; + } + int a; + for(a = a0; a < n; a++) { + int ap = a*2 - (subtype == ONE_SIDED ? 0 : (n-1)); + int remap = (a == (n - 1)) ? REMAP_LAST : a; + + thisMesh.Clear(); + if(type == TRANSLATE) { + Vector trans = Vector::From(h.param(0), h.param(1), h.param(2)); + trans = trans.ScaledBy(ap); + for(int i = 0; i < srcm->l.n; i++) { + STriangle tr = srcm->l.elem[i]; + tr.a = (tr.a).Plus(trans); + tr.b = (tr.b).Plus(trans); + tr.c = (tr.c).Plus(trans); + if(tr.meta.face != 0) { + hEntity he = { tr.meta.face }; + tr.meta.face = Remap(he, remap).v; + } + thisMesh.AddTriangle(&tr); + } + } else { + Vector trans = Vector::From(h.param(0), h.param(1), h.param(2)); + double theta = ap * SS.GetParam(h.param(3))->val; + double c = cos(theta), s = sin(theta); + Vector axis = Vector::From(h.param(4), h.param(5), h.param(6)); + Quaternion q = Quaternion::From(c, s*axis.x, s*axis.y, s*axis.z); + + for(int i = 0; i < srcm->l.n; i++) { + STriangle tr = srcm->l.elem[i]; + tr.a = (q.Rotate((tr.a).Minus(trans))).Plus(trans); + tr.b = (q.Rotate((tr.b).Minus(trans))).Plus(trans); + tr.c = (q.Rotate((tr.c).Minus(trans))).Plus(trans); + if(tr.meta.face != 0) { + hEntity he = { tr.meta.face }; + tr.meta.face = Remap(he, remap).v; + } + thisMesh.AddTriangle(&tr); + } + } + + runningMesh.Clear(); + if(src->meshCombine == COMBINE_AS_DIFFERENCE) { + runningMesh.MakeFromDifference(&origm, &thisMesh); + } else { + runningMesh.MakeFromUnion(&origm, &thisMesh); + } + origm.Clear(); + origm.MakeFromCopy(&runningMesh); + } + origm.Clear(); + thisMesh.Clear(); +} + void Group::GenerateMeshForSweep(void) { STriMeta meta = { 0, color }; SEdgeList edges; @@ -239,6 +310,11 @@ void Group::GenerateMesh(void) { thisMesh.Clear(); STriMeta meta = { 0, color }; + if(type == TRANSLATE || type == ROTATE) { + GenerateMeshForStepAndRepeat(); + return; + } + if(type == EXTRUDE) { SEdgeList edges; ZERO(&edges); @@ -384,9 +460,17 @@ void Group::GenerateMesh(void) { } } + runningMesh.Clear(); + + // If this group contributes no new mesh, then our running mesh is the + // same as last time, no combining required. + if(thisMesh.l.n == 0) { + runningMesh.MakeFromCopy(PreviousGroupMesh()); + return; + } + // So our group's mesh appears in thisMesh. Combine this with the previous // group's mesh, using the requested operation. - runningMesh.Clear(); bool prevMeshError = meshError.yes; meshError.yes = false; meshError.interferesAt.Clear(); @@ -424,7 +508,7 @@ void Group::Draw(void) { // to show or hide just this with the "show solids" flag. int specColor; - if(type != EXTRUDE && type != IMPORTED && type != LATHE && type != SWEEP) { + if(type == DRAWING_3D || type == DRAWING_WORKPLANE) { specColor = RGB(25, 25, 25); // force the color to something dim } else { specColor = -1; // use the model color diff --git a/mesh.cpp b/mesh.cpp index e83518dd..08fa570c 100644 --- a/mesh.cpp +++ b/mesh.cpp @@ -256,6 +256,13 @@ bool SMesh::MakeFromInterferenceCheck(SMesh *srca, SMesh *srcb, SMesh *error) { return (error->l.n == 0); } +void SMesh::MakeFromCopy(SMesh *a) { + int i; + for(i = 0; i < a->l.n; i++) { + AddTriangle(&(a->l.elem[i])); + } +} + DWORD SMesh::FirstIntersectionWith(Point2d mp) { Vector p0 = Vector::From(mp.x, mp.y, 0); Vector gn = Vector::From(0, 0, 1); diff --git a/polygon.h b/polygon.h index 4626d38d..9b896ac1 100644 --- a/polygon.h +++ b/polygon.h @@ -204,6 +204,7 @@ public: void MakeFromUnion(SMesh *a, SMesh *b); void MakeFromDifference(SMesh *a, SMesh *b); bool MakeFromInterferenceCheck(SMesh *srca, SMesh *srcb, SMesh *errorAt); + void MakeFromCopy(SMesh *a); DWORD FirstIntersectionWith(Point2d mp); }; diff --git a/sketch.h b/sketch.h index 4cddf0a3..51653f48 100644 --- a/sketch.h +++ b/sketch.h @@ -189,6 +189,7 @@ public: void GetTrajectory(hGroup hg, SContour *traj, SPolygon *section); void AddQuadWithNormal(STriMeta meta, Vector out, Vector a, Vector b, Vector c, Vector d); + void GenerateMeshForStepAndRepeat(void); void GenerateMeshForSweep(void); void GenerateMesh(void); void Draw(void); @@ -258,6 +259,8 @@ public: static const int FACE_NORMAL_PT = 5000; static const int FACE_XPROD = 5001; static const int FACE_N_ROT_TRANS = 5002; + static const int FACE_N_TRANS = 5003; + static const int FACE_N_ROT_AA = 5004; static const int WORKPLANE = 10000; @@ -304,6 +307,8 @@ public: // times to apply the transformation. int timesApplied; + Quaternion GetAxisAngleQuaternion(int param0); + ExprQuaternion GetAxisAngleQuaternionExprs(int param0); bool IsVisible(void); bool IsCircle(void); diff --git a/textwin.cpp b/textwin.cpp index ed9e09b1..f7b807c7 100644 --- a/textwin.cpp +++ b/textwin.cpp @@ -322,6 +322,8 @@ void TextWindow::DescribeSelection(void) { case Entity::FACE_NORMAL_PT: case Entity::FACE_XPROD: case Entity::FACE_N_ROT_TRANS: + case Entity::FACE_N_ROT_AA: + case Entity::FACE_N_TRANS: Printf(false, "%FtPLANE FACE%E"); p = e->FaceGetNormalNum(); Printf(true, " normal = " PT_AS_NUM, CO(p)); diff --git a/wishlist.txt b/wishlist.txt index 2f471937..75f05ec7 100644 --- a/wishlist.txt +++ b/wishlist.txt @@ -8,6 +8,7 @@ remove back button in browser? relative paths for import auto-generate circles and faces when lathing copy the section geometry to other end when sweeping +cylindrical faces partitioned subsystems in the solver