From 6dced8052b72e7ef36728ee01f5f45f4bcd1dcba Mon Sep 17 00:00:00 2001 From: EvilSpirit Date: Sat, 31 Oct 2015 14:22:26 +0600 Subject: [PATCH] Generate primitives for lathe groups. The primitives that are generated are circles from points and faces from axis-perpendicular line segments. --- src/drawentity.cpp | 1 + src/group.cpp | 111 +++++++++++++++++++++++++++++++++++++++++++- src/groupmesh.cpp | 2 +- src/sketch.h | 7 ++- src/solvespace.h | 1 + src/srf/surface.cpp | 10 +++- src/srf/surface.h | 3 +- 7 files changed, 130 insertions(+), 5 deletions(-) diff --git a/src/drawentity.cpp b/src/drawentity.cpp index 743ce51..fbbea00 100644 --- a/src/drawentity.cpp +++ b/src/drawentity.cpp @@ -366,6 +366,7 @@ void Entity::GenerateBezierCurves(SBezierList *sbl) { Vector a = SK.GetEntity(point[0])->PointGetNum(); Vector b = SK.GetEntity(point[1])->PointGetNum(); sb = SBezier::From(a, b); + sb.entity = h.v; sbl->l.Add(&sb); break; } diff --git a/src/group.cpp b/src/group.cpp index 6333696..3ec4904 100644 --- a/src/group.cpp +++ b/src/group.cpp @@ -283,7 +283,7 @@ std::string Group::DescriptionString(void) { } void Group::Activate(void) { - if(type == EXTRUDE || type == IMPORTED) { + if(type == EXTRUDE || type == IMPORTED || type == LATHE || type == TRANSLATE || type == ROTATE) { SS.GW.showFaces = true; } else { SS.GW.showFaces = false; @@ -390,6 +390,43 @@ void Group::Generate(IdList *entity, } case LATHE: { + Vector axis_pos = SK.GetEntity(predef.origin)->PointGetNum(); + Vector axis_dir = SK.GetEntity(predef.entityB)->VectorGetNum(); + + AddParam(param, h.param(0), axis_dir.x); + AddParam(param, h.param(1), axis_dir.y); + AddParam(param, h.param(2), axis_dir.z); + + // Remapped entity index. + int ai = 1; + + for(i = 0; i < entity->n; i++) { + Entity *e = &(entity->elem[i]); + if(e->group.v != opA.v) continue; + + e->CalculateNumerical(false); + hEntity he = e->h; + + // As soon as I call CopyEntity, e may become invalid! That + // adds entities, which may cause a realloc. + CopyEntity(entity, SK.GetEntity(predef.origin), 0, ai, + h.param(0), h.param(1), h.param(2), + NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, + true, false); + + CopyEntity(entity, SK.GetEntity(he), 0, REMAP_LATHE_START, + h.param(0), h.param(1), h.param(2), + NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, + true, false); + + CopyEntity(entity, SK.GetEntity(he), 0, REMAP_LATHE_END, + h.param(0), h.param(1), h.param(2), + NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, + true, false); + + MakeLatheCircles(entity, param, he, axis_pos, axis_dir, ai); + ai++; + } break; } @@ -600,6 +637,78 @@ void Group::MakeExtrusionLines(IdList *el, hEntity in) { } } +void Group::MakeLatheCircles(IdList *el, IdList *param, hEntity in, Vector pt, Vector axis, int ai) { + Entity *ep = SK.GetEntity(in); + + Entity en = {}; + if(ep->IsPoint()) { + // A point gets revolved to form an arc. + en.point[0] = Remap(predef.origin, ai); + en.point[1] = Remap(ep->h, REMAP_LATHE_START); + en.point[2] = Remap(ep->h, REMAP_LATHE_END); + + // Get arc center and point on arc. + Entity *pc = SK.GetEntity(en.point[0]); + Entity *pp = SK.GetEntity(en.point[1]); + + // Project arc point to the revolution axis and use it for arc center. + double k = pp->numPoint.Minus(pt).Dot(axis) / axis.Dot(axis); + pc->numPoint = pt.Plus(axis.ScaledBy(k)); + + // Create arc entity. + en.group = h; + en.construction = ep->construction; + en.style = ep->style; + en.h = Remap(ep->h, REMAP_PT_TO_ARC); + en.type = Entity::ARC_OF_CIRCLE; + + // Generate a normal. + Entity n = {}; + n.workplane = en.workplane; + n.h = Remap(ep->h, REMAP_PT_TO_NORMAL); + n.group = en.group; + n.style = en.style; + n.type = Entity::NORMAL_N_COPY; + + // Create basis for the normal. + Vector nu = pp->numPoint.Minus(pc->numPoint).WithMagnitude(1.0); + Vector nv = nu.Cross(axis).WithMagnitude(1.0); + n.numNormal = Quaternion::From(nv, nu); + + // The point determines where the normal gets displayed on-screen; + // it's entirely cosmetic. + n.point[0] = en.point[0]; + el->Add(&n); + en.normal = n.h; + el->Add(&en); + } else if(ep->type == Entity::LINE_SEGMENT) { + // An axis-perpendicular line gets revolved to form a face. + Vector a = SK.GetEntity(ep->point[0])->PointGetNum(); + Vector b = SK.GetEntity(ep->point[1])->PointGetNum(); + Vector u = b.Minus(a).WithMagnitude(1.0); + + // Check for perpendicularity: calculate cosine of the angle + // between axis and line direction and check that + // cos(angle) == 0 <-> angle == +-90 deg. + if(fabs(u.Dot(axis) / axis.Magnitude()) < ANGLE_COS_EPS) { + en.param[0] = h.param(0); + en.param[1] = h.param(1); + en.param[2] = h.param(2); + Vector v = axis.Cross(u).WithMagnitude(1.0); + Vector n = u.Cross(v); + en.numNormal = Quaternion::From(0, n.x, n.y, n.z); + + en.group = h; + en.construction = ep->construction; + en.style = ep->style; + en.h = Remap(ep->h, REMAP_LINE_TO_FACE); + en.type = Entity::FACE_NORMAL_PT; + en.point[0] = ep->point[0]; + el->Add(&en); + } + } +} + void Group::MakeExtrusionTopBottomFaces(IdList *el, hEntity pt) { if(pt.v == 0) return; diff --git a/src/groupmesh.cpp b/src/groupmesh.cpp index 90e235b..d6d1f1a 100644 --- a/src/groupmesh.cpp +++ b/src/groupmesh.cpp @@ -283,7 +283,7 @@ void Group::GenerateShellAndMesh(void) { SBezierLoopSetSet *sblss = &(src->bezierLoops); SBezierLoopSet *sbls; for(sbls = sblss->l.First(); sbls; sbls = sblss->l.NextAfter(sbls)) { - thisShell.MakeFromRevolutionOf(sbls, pt, axis, color); + thisShell.MakeFromRevolutionOf(sbls, pt, axis, color, this); } } else if(type == IMPORTED) { // The imported shell or mesh are copied over, with the appropriate diff --git a/src/sketch.h b/src/sketch.h index b86200b..c14bd43 100644 --- a/src/sketch.h +++ b/src/sketch.h @@ -214,10 +214,15 @@ public: REMAP_TOP = 1001, REMAP_BOTTOM = 1002, REMAP_PT_TO_LINE = 1003, - REMAP_LINE_TO_FACE = 1004 + REMAP_LINE_TO_FACE = 1004, + REMAP_LATHE_START = 1006, + REMAP_LATHE_END = 1007, + REMAP_PT_TO_ARC = 1008, + REMAP_PT_TO_NORMAL = 1009, }; hEntity Remap(hEntity in, int copyNumber); void MakeExtrusionLines(EntityList *el, hEntity in); + void MakeLatheCircles(IdList *el, IdList *param, hEntity in, Vector pt, Vector axis, int ai); void MakeExtrusionTopBottomFaces(EntityList *el, hEntity pt); void CopyEntity(EntityList *el, Entity *ep, int timesApplied, int remap, diff --git a/src/solvespace.h b/src/solvespace.h index 2b961f5..31972d0 100644 --- a/src/solvespace.h +++ b/src/solvespace.h @@ -94,6 +94,7 @@ inline double ffabs(double v) { return (v > 0) ? v : (-v); } #define CO(v) (v).x, (v).y, (v).z +#define ANGLE_COS_EPS (1e-6) #define LENGTH_EPS (1e-6) #define VERY_POSITIVE (1e10) #define VERY_NEGATIVE (-1e10) diff --git a/src/srf/surface.cpp b/src/srf/surface.cpp index c18fcc5..5e162b6 100644 --- a/src/srf/surface.cpp +++ b/src/srf/surface.cpp @@ -600,7 +600,7 @@ typedef struct { hSSurface d[4]; } Revolved; -void SShell::MakeFromRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis, RgbaColor color) +void SShell::MakeFromRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis, RgbaColor color, Group *group) { SBezierLoop *sbl; @@ -654,6 +654,14 @@ void SShell::MakeFromRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis, (PI/2)*j, (PI/2)*(j+1)); ss.color = color; + if(sb->entity != 0) { + hEntity he; + he.v = sb->entity; + hEntity hface = group->Remap(he, Group::REMAP_LINE_TO_FACE); + if(SK.entity.FindByIdNoOops(hface) != NULL) { + ss.face = hface.v; + } + } revs.d[j] = surface.AddAndAssignId(&ss); } } diff --git a/src/srf/surface.h b/src/srf/surface.h index af7bc40..e2f2bee 100644 --- a/src/srf/surface.h +++ b/src/srf/surface.h @@ -77,6 +77,7 @@ public: int deg; Vector ctrl[4]; double weight[4]; + uint32_t entity; Vector PointAt(double t); Vector TangentAt(double t); @@ -363,7 +364,7 @@ public: void MakeFromExtrusionOf(SBezierLoopSet *sbls, Vector t0, Vector t1, RgbaColor color); void MakeFromRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis, - RgbaColor color); + RgbaColor color, Group *group); void MakeFromUnionOf(SShell *a, SShell *b); void MakeFromDifferenceOf(SShell *a, SShell *b);