Implement helical extrusion groups.

pull/456/head
phkahler 2019-07-07 15:39:33 -04:00 committed by whitequark
parent b3f739f2c4
commit 986da7d224
12 changed files with 218 additions and 44 deletions

View File

@ -5,7 +5,7 @@ Changelog
---
New sketch features:
* New group, revolve.
* New groups, revolution and helical extrusion.
* Extrude, lathe, translate and rotate groups can use the "assembly"
boolean operation, to increase performance.
* The solid model of extrude and lathe groups can be suppressed,

View File

@ -88,6 +88,7 @@ void Entity::GetReferencePoints(std::vector<Vector> *refs) {
case Type::POINT_N_TRANS:
case Type::POINT_N_ROT_TRANS:
case Type::POINT_N_ROT_AA:
case Type::POINT_N_ROT_AXIS_TRANS:
case Type::POINT_IN_3D:
case Type::POINT_IN_2D:
refs->push_back(PointGetNum());
@ -502,6 +503,7 @@ void Entity::Draw(DrawAs how, Canvas *canvas) {
case Type::POINT_N_TRANS:
case Type::POINT_N_ROT_TRANS:
case Type::POINT_N_ROT_AA:
case Type::POINT_N_ROT_AXIS_TRANS:
case Type::POINT_IN_3D:
case Type::POINT_IN_2D: {
if(how == DrawAs::HIDDEN) return;

View File

@ -245,6 +245,7 @@ bool EntityBase::IsPoint() const {
case Type::POINT_N_TRANS:
case Type::POINT_N_ROT_TRANS:
case Type::POINT_N_ROT_AA:
case Type::POINT_N_ROT_AXIS_TRANS:
return true;
default:
@ -454,10 +455,38 @@ void EntityBase::PointForceTo(Vector p) {
// in order to avoid jumps when you cross from +pi to -pi
while(dtheta < -PI) dtheta += 2*PI;
while(dtheta > PI) dtheta -= 2*PI;
// this extra *2 explains the mystery *4
SK.GetParam(param[3])->val = (thetai + dtheta)/(timesApplied*2);
break;
}
case Type::POINT_N_ROT_AXIS_TRANS: {
if(timesApplied == 0) break;
// is the point on the rotation axis?
Vector offset = Vector::From(param[0], param[1], param[2]);
Vector normal = Vector::From(param[4], param[5], param[6]).WithMagnitude(1.0);
Vector check = numPoint.Minus(offset).Cross(normal);
if (check.Dot(check) < LENGTH_EPS) { // if so, do extrusion style drag
Vector trans = (p.Minus(numPoint));
SK.GetParam(param[7])->val = trans.Dot(normal)/timesApplied;
} else { // otherwise do rotation style
Vector u = normal.Normal(0), v = normal.Normal(1);
Vector po = p.Minus(offset), numo = numPoint.Minus(offset);
double thetap = atan2(v.Dot(po), u.Dot(po));
double thetan = atan2(v.Dot(numo), u.Dot(numo));
double thetaf = (thetap - thetan);
double thetai = (SK.GetParam(param[3])->val)*timesApplied*2;
double dtheta = thetaf - thetai;
// Take the smallest possible change in the actual step angle,
// in order to avoid jumps when you cross from +pi to -pi
while(dtheta < -PI) dtheta += 2*PI;
while(dtheta > PI) dtheta -= 2*PI;
// this extra *2 explains the mystery *4
SK.GetParam(param[3])->val = (thetai + dtheta)/(timesApplied*2);
}
break;
}
case Type::POINT_N_COPY:
// Nothing to do; it's a static copy
break;
@ -506,6 +535,17 @@ Vector EntityBase::PointGetNum() const {
break;
}
case Type::POINT_N_ROT_AXIS_TRANS: {
Vector offset = Vector::From(param[0], param[1], param[2]);
Vector displace = Vector::From(param[4], param[5], param[6])
.WithMagnitude(SK.GetParam(param[7])->val).ScaledBy(timesApplied);
Quaternion q = PointGetQuaternion();
p = numPoint.Minus(offset);
p = q.Rotate(p);
p = p.Plus(offset).Plus(displace);
break;
}
case Type::POINT_N_COPY:
p = numPoint;
break;
@ -555,6 +595,18 @@ ExprVector EntityBase::PointGetExprs() const {
r = orig.Plus(trans);
break;
}
case Type::POINT_N_ROT_AXIS_TRANS: {
ExprVector orig = ExprVector::From(numPoint);
ExprVector trans = ExprVector::From(param[0], param[1], param[2]);
ExprVector displace = ExprVector::From(param[4], param[5], param[6])
.WithMagnitude(Expr::From(1.0)).ScaledBy(Expr::From(timesApplied)).ScaledBy(Expr::From(param[7]));
ExprQuaternion q = GetAxisAngleQuaternionExprs(3);
orig = orig.Minus(trans);
orig = q.Rotate(orig);
r = orig.Plus(trans).Plus(displace);
break;
}
case Type::POINT_N_COPY:
r = ExprVector::From(numPoint);
break;
@ -633,7 +685,7 @@ ExprQuaternion EntityBase::GetAxisAngleQuaternionExprs(int param0) const {
Quaternion EntityBase::PointGetQuaternion() const {
Quaternion q;
if(type == Type::POINT_N_ROT_AA) {
if(type == Type::POINT_N_ROT_AA || type == Type::POINT_N_ROT_AXIS_TRANS) {
q = GetAxisAngleQuaternion(3);
} else if(type == Type::POINT_N_ROT_TRANS) {
q = Quaternion::From(param[3], param[4], param[5], param[6]);
@ -807,7 +859,7 @@ bool EntityBase::IsInPlane(Vector norm, double distance) const {
case Type::CIRCLE:
case Type::ARC_OF_CIRCLE: {
// If it is an (arc of) a circle, check whether the normals
// If it is an (arc of) a circle, check whether the normals
// are parallel and the mid point is in the plane.
Vector n = Normal()->NormalN();
if (!norm.Equals(n) && !norm.Equals(n.Negated())) return false;

View File

@ -445,6 +445,7 @@ void SolveSpaceUI::MarkDraggedParams() {
switch(pt->type) {
case Entity::Type::POINT_N_TRANS:
case Entity::Type::POINT_IN_3D:
case Entity::Type::POINT_N_ROT_AXIS_TRANS:
sys.dragged.Add(&(pt->param[0]));
sys.dragged.Add(&(pt->param[1]));
sys.dragged.Add(&(pt->param[2]));

View File

@ -105,6 +105,7 @@ const MenuEntry Menu[] = {
{ 1, N_("Step &Rotating"), Command::GROUP_ROT, S|'r', KN, mGrp },
{ 1, NULL, Command::NONE, 0, KN, NULL },
{ 1, N_("E&xtrude"), Command::GROUP_EXTRUDE, S|'x', KN, mGrp },
{ 1, N_("&Helix"), Command::GROUP_HELIX, S|'h', KN, mGrp },
{ 1, N_("&Lathe"), Command::GROUP_LATHE, S|'l', KN, mGrp },
{ 1, N_("Re&volve"), Command::GROUP_REVOLVE, S|'v', KN, mGrp },
{ 1, NULL, Command::NONE, 0, KN, NULL },

View File

@ -208,6 +208,30 @@ void Group::MenuGroup(Command id, Platform::Path linkFile) {
g.name = C_("group-name", "revolve");
break;
case Command::GROUP_HELIX:
if(gs.points == 1 && gs.vectors == 1 && gs.n == 2) {
g.predef.origin = gs.point[0];
g.predef.entityB = gs.vector[0];
} else if(gs.lineSegments == 1 && gs.n == 1) {
g.predef.origin = SK.GetEntity(gs.entity[0])->point[0];
g.predef.entityB = gs.entity[0];
// since a line segment is a vector
} else {
Error(_("Bad selection for new helix group. This group can "
"be created with:\n\n"
" * a point and a line segment or normal "
"(revolved about an axis parallel to line / "
"normal, through point)\n"
" * a line segment (revolved about line segment)\n"));
return;
}
g.type = Type::HELIX;
g.opA = SS.GW.activeGroup;
g.valA = 2;
g.subtype = Subtype::ONE_SIDED;
g.name = C_("group-name", "helix");
break;
case Command::GROUP_ROT: {
if(gs.points == 1 && gs.n == 1 && SS.GW.LockedInWorkplane()) {
g.predef.origin = gs.point[0];
@ -368,7 +392,7 @@ std::string Group::DescriptionString() {
void Group::Activate() {
if(type == Type::EXTRUDE || type == Type::LINKED || type == Type::LATHE ||
type == Type::REVOLVE || type == Type::TRANSLATE || type == Type::ROTATE) {
type == Type::REVOLVE || type == Type::HELIX || type == Type::TRANSLATE || type == Type::ROTATE) {
SS.GW.showFaces = true;
} else {
SS.GW.showFaces = false;
@ -460,11 +484,11 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
// adds entities, which may cause a realloc.
CopyEntity(entity, SK.GetEntity(he), ai, REMAP_BOTTOM,
h.param(0), h.param(1), h.param(2),
NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM,
NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM,
CopyAs::N_TRANS);
CopyEntity(entity, SK.GetEntity(he), af, REMAP_TOP,
h.param(0), h.param(1), h.param(2),
NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM,
NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM,
CopyAs::N_TRANS);
MakeExtrusionLines(entity, he);
}
@ -492,17 +516,17 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
// adds entities, which may cause a realloc.
CopyEntity(entity, SK.GetEntity(predef.origin), 0, ai,
NO_PARAM, NO_PARAM, NO_PARAM,
NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM,
NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM,
CopyAs::NUMERIC);
CopyEntity(entity, SK.GetEntity(he), 0, REMAP_LATHE_START,
NO_PARAM, NO_PARAM, NO_PARAM,
NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM,
NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM,
CopyAs::NUMERIC);
CopyEntity(entity, SK.GetEntity(he), 0, REMAP_LATHE_END,
NO_PARAM, NO_PARAM, NO_PARAM,
NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM,
NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM,
CopyAs::NUMERIC);
MakeLatheCircles(entity, param, he, axis_pos, axis_dir, ai);
@ -527,7 +551,6 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
AddParam(param, h.param(5), axis_dir.y);
AddParam(param, h.param(6), axis_dir.z);
int n = 2;
int ai = 1;
for(i = 0; i < entity->n; i++) {
@ -539,17 +562,17 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
hEntity he = e->h;
CopyEntity(entity, SK.GetEntity(predef.origin), 0, ai, NO_PARAM, NO_PARAM,
NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, CopyAs::NUMERIC);
NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, CopyAs::NUMERIC);
for(a = 0; a < 2; a++) {
if(e->group != opA)
continue;
e->CalculateNumerical(false);
CopyEntity(entity, e, a * 2 - (subtype == Subtype::ONE_SIDED ? 0 : (n - 1)),
(a == (n - 1)) ? REMAP_LATHE_END : REMAP_LATHE_START, h.param(0),
h.param(1), h.param(2), h.param(3), h.param(4), h.param(5),
h.param(6), CopyAs::N_ROT_AA);
CopyEntity(entity, e, a * 2 - (subtype == Subtype::ONE_SIDED ? 0 : 1),
(a == 1) ? REMAP_LATHE_END : REMAP_LATHE_START, h.param(0),
h.param(1), h.param(2), h.param(3), h.param(4), h.param(5),
h.param(6), NO_PARAM, CopyAs::N_ROT_AA);
}
// Arcs are not generated for revolve groups, for now, because our current arc
// entity is not chiral, and dragging a revolve may break the arc by inverting it.
@ -561,6 +584,63 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
return;
}
case Type::HELIX: {
Vector axis_pos = SK.GetEntity(predef.origin)->PointGetNum();
Vector axis_dir = SK.GetEntity(predef.entityB)->VectorGetNum();
// The center of rotation
AddParam(param, h.param(0), axis_pos.x);
AddParam(param, h.param(1), axis_pos.y);
AddParam(param, h.param(2), axis_pos.z);
// The rotation quaternion
AddParam(param, h.param(3), 30 * PI / 180);
AddParam(param, h.param(4), axis_dir.x);
AddParam(param, h.param(5), axis_dir.y);
AddParam(param, h.param(6), axis_dir.z);
// distance to translate along the rotation axis
AddParam(param, h.param(7), 20);
int ai = 1;
for(i = 0; i < entity->n; i++) {
Entity *e = &(entity->elem[i]);
if(e->group.v != opA.v)
continue;
e->CalculateNumerical(/*forExport=*/false);
CopyEntity(entity, SK.GetEntity(predef.origin), 0, ai, NO_PARAM, NO_PARAM,
NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, CopyAs::NUMERIC);
for(a = 0; a < 2; a++) {
e->CalculateNumerical(false);
CopyEntity(entity, e, a * 2 - (subtype == Subtype::ONE_SIDED ? 0 : 1),
(a == 1) ? REMAP_LATHE_END : REMAP_LATHE_START, h.param(0),
h.param(1), h.param(2), h.param(3), h.param(4), h.param(5),
h.param(6), h.param(7), CopyAs::N_ROT_AXIS_TRANS);
}
// For point entities on the axis, create a construction line
if(e->IsPoint()) {
Vector check = e->PointGetNum().Minus(axis_pos).Cross(axis_dir);
if (check.Dot(check) < LENGTH_EPS) {
Entity *ep = SK.GetEntity(e->h);
Entity en = {};
// A point gets extruded to form a line segment
en.point[0] = Remap(ep->h, REMAP_LATHE_START);
en.point[1] = Remap(ep->h, REMAP_LATHE_END);
en.group = h;
en.construction = ep->construction;
en.style = ep->style;
en.h = Remap(ep->h, REMAP_PT_TO_LINE);
en.type = Entity::Type::LINE_SEGMENT;
entity->Add(&en);
}
}
ai++;
}
return;
}
case Type::TRANSLATE: {
// inherit meshCombine from source group
Group *srcg = SK.GetGroup(opA);
@ -585,7 +665,7 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
a*2 - (subtype == Subtype::ONE_SIDED ? 0 : (n-1)),
(a == (n - 1)) ? REMAP_LAST : a,
h.param(0), h.param(1), h.param(2),
NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM,
NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM,
CopyAs::N_TRANS);
}
}
@ -620,7 +700,7 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
a*2 - (subtype == Subtype::ONE_SIDED ? 0 : (n-1)),
(a == (n - 1)) ? REMAP_LAST : a,
h.param(0), h.param(1), h.param(2),
h.param(3), h.param(4), h.param(5), h.param(6),
h.param(3), h.param(4), h.param(5), h.param(6), NO_PARAM,
CopyAs::N_ROT_AA);
}
}
@ -641,7 +721,7 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
Entity *ie = &(impEntity.elem[i]);
CopyEntity(entity, ie, 0, 0,
h.param(0), h.param(1), h.param(2),
h.param(3), h.param(4), h.param(5), h.param(6),
h.param(3), h.param(4), h.param(5), h.param(6), NO_PARAM,
CopyAs::N_ROT_TRANS);
}
return;
@ -670,7 +750,7 @@ void Group::GenerateEquations(IdList<Equation,hEquation> *l) {
Expr::From(h.param(5)),
Expr::From(h.param(6)) };
AddEq(l, (q.Magnitude())->Minus(Expr::From(1)), 0);
} else if(type == Type::ROTATE || type == Type::REVOLVE) {
} else if(type == Type::ROTATE || type == Type::REVOLVE || type == Type::HELIX) {
// The axis and center of rotation are specified numerically
#define EC(x) (Expr::From(x))
#define EP(x) (Expr::From(h.param(x)))
@ -867,7 +947,7 @@ void Group::MakeExtrusionTopBottomFaces(IdList<Entity,hEntity> *el, hEntity pt)
void Group::CopyEntity(IdList<Entity,hEntity> *el,
Entity *ep, int timesApplied, int remap,
hParam dx, hParam dy, hParam dz,
hParam qw, hParam qvx, hParam qvy, hParam qvz,
hParam qw, hParam qvx, hParam qvy, hParam qvz, hParam dist,
CopyAs as)
{
Entity en = {};
@ -891,6 +971,7 @@ void Group::CopyEntity(IdList<Entity,hEntity> *el,
case Entity::Type::POINT_N_TRANS:
case Entity::Type::POINT_N_ROT_TRANS:
case Entity::Type::POINT_N_ROT_AA:
case Entity::Type::POINT_N_ROT_AXIS_TRANS:
case Entity::Type::POINT_IN_3D:
case Entity::Type::POINT_IN_2D:
if(as == CopyAs::N_TRANS) {
@ -903,6 +984,8 @@ void Group::CopyEntity(IdList<Entity,hEntity> *el,
} else {
if(as == CopyAs::N_ROT_AA) {
en.type = Entity::Type::POINT_N_ROT_AA;
} else if (as == CopyAs::N_ROT_AXIS_TRANS) {
en.type = Entity::Type::POINT_N_ROT_AXIS_TRANS;
} else {
en.type = Entity::Type::POINT_N_ROT_TRANS;
}
@ -913,6 +996,9 @@ void Group::CopyEntity(IdList<Entity,hEntity> *el,
en.param[4] = qvx;
en.param[5] = qvy;
en.param[6] = qvz;
if (as == CopyAs::N_ROT_AXIS_TRANS) {
en.param[7] = dist;
}
}
en.numPoint = (ep->actPoint).ScaledBy(scale);
break;
@ -924,8 +1010,8 @@ void Group::CopyEntity(IdList<Entity,hEntity> *el,
case Entity::Type::NORMAL_IN_2D:
if(as == CopyAs::N_TRANS || as == CopyAs::NUMERIC) {
en.type = Entity::Type::NORMAL_N_COPY;
} else {
if(as == CopyAs::N_ROT_AA) {
} else { // N_ROT_AXIS_TRANS probably doesn't warrant a new entity Type
if(as == CopyAs::N_ROT_AA || as == CopyAs::N_ROT_AXIS_TRANS) {
en.type = Entity::Type::NORMAL_N_ROT_AA;
} else {
en.type = Entity::Type::NORMAL_N_ROT;
@ -960,7 +1046,7 @@ void Group::CopyEntity(IdList<Entity,hEntity> *el,
} else if (as == CopyAs::NUMERIC) {
en.type = Entity::Type::FACE_NORMAL_PT;
} else {
if(as == CopyAs::N_ROT_AA) {
if(as == CopyAs::N_ROT_AA || as == CopyAs::N_ROT_AXIS_TRANS) {
en.type = Entity::Type::FACE_N_ROT_AA;
} else {
en.type = Entity::Type::FACE_N_ROT_TRANS;

View File

@ -296,6 +296,7 @@ void Group::GenerateShellAndMesh() {
} else if(type == Type::REVOLVE && haveSrc) {
Group *src = SK.GetGroup(opA);
double anglef = SK.GetParam(h.param(3))->val * 4; // why the 4 is needed?
double dists = 0, distf = 0;
double angles = 0.0;
if(subtype != Subtype::ONE_SIDED) {
anglef *= 0.5;
@ -309,11 +310,34 @@ void Group::GenerateShellAndMesh() {
SBezierLoopSet *sbls;
for(sbls = sblss->l.First(); sbls; sbls = sblss->l.NextAfter(sbls)) {
if(fabs(anglef - angles) < 2 * PI) {
thisShell.MakeFromHelicalRevolutionOf(sbls, pt, axis, color, this, angles, anglef);
thisShell.MakeFromHelicalRevolutionOf(sbls, pt, axis, color, this,
angles, anglef, dists, distf);
} else {
thisShell.MakeFromRevolutionOf(sbls, pt, axis, color, this);
}
}
} else if(type == Type::HELIX && haveSrc) {
Group *src = SK.GetGroup(opA);
double anglef = SK.GetParam(h.param(3))->val * 4; // why the 4 is needed?
double dists = 0, distf = 0;
double angles = 0.0;
distf = SK.GetParam(h.param(7))->val * 2; // dist is applied twice
if(subtype != Subtype::ONE_SIDED) {
anglef *= 0.5;
angles = -anglef;
distf *= 0.5;
dists = -distf;
}
Vector pt = SK.GetEntity(predef.origin)->PointGetNum(),
axis = SK.GetEntity(predef.entityB)->VectorGetNum();
axis = axis.WithMagnitude(1);
SBezierLoopSetSet *sblss = &(src->bezierLoops);
SBezierLoopSet *sbls;
for(sbls = sblss->l.First(); sbls; sbls = sblss->l.NextAfter(sbls)) {
thisShell.MakeFromHelicalRevolutionOf(sbls, pt, axis, color, this,
angles, anglef, dists, distf);
}
} else if(type == Type::LINKED) {
// The imported shell or mesh are copied over, with the appropriate
// transformation applied. We also must remap the face entities.
@ -488,6 +512,7 @@ bool Group::IsMeshGroup() {
case Group::Type::EXTRUDE:
case Group::Type::LATHE:
case Group::Type::REVOLVE:
case Group::Type::HELIX:
case Group::Type::ROTATE:
case Group::Type::TRANSLATE:
return true;

View File

@ -151,6 +151,7 @@ public:
N_TRANS,
N_ROT_AA,
N_ROT_TRANS,
N_ROT_AXIS_TRANS,
};
enum class Type : uint32_t {
@ -159,6 +160,7 @@ public:
EXTRUDE = 5100,
LATHE = 5101,
REVOLVE = 5102,
HELIX = 5103,
ROTATE = 5200,
TRANSLATE = 5201,
LINKED = 5300
@ -286,7 +288,7 @@ public:
void CopyEntity(EntityList *el,
Entity *ep, int timesApplied, int remap,
hParam dx, hParam dy, hParam dz,
hParam qw, hParam qvx, hParam qvy, hParam qvz,
hParam qw, hParam qvx, hParam qvy, hParam qvz, hParam dist,
CopyAs as);
void AddEq(IdList<Equation,hEquation> *l, Expr *expr, int index);
@ -387,6 +389,7 @@ public:
POINT_N_ROT_TRANS = 2011,
POINT_N_COPY = 2012,
POINT_N_ROT_AA = 2013,
POINT_N_ROT_AXIS_TRANS = 2014,
NORMAL_IN_3D = 3000,
NORMAL_IN_2D = 3001,
@ -426,7 +429,7 @@ public:
hEntity distance;
// The only types that have their own params are points, normals,
// and directions.
hParam param[7];
hParam param[8];
// Transformed points/normals/distances have their numerical base
Vector numPoint;

View File

@ -606,8 +606,8 @@ void SShell::MakeFromExtrusionOf(SBezierLoopSet *sbls, Vector t0, Vector t1, Rgb
}
}
bool SShell::CheckNormalAxisRelationship(SBezierLoopSet *sbls, Vector pt, Vector axis)
// Check that the direction of revolution ends up parallel to the normal of
bool SShell::CheckNormalAxisRelationship(SBezierLoopSet *sbls, Vector pt, Vector axis, double da, double dx)
// Check that the direction of revolution/extrusion ends up parallel to the normal of
// the sketch, on the side of the axis where the sketch is.
{
SBezierLoop *sbl;
@ -631,9 +631,10 @@ bool SShell::CheckNormalAxisRelationship(SBezierLoopSet *sbls, Vector pt, Vector
}
}
Vector ptc = pto.ClosestPointOnLine(pt, axis),
up = (pto.Minus(ptc)).WithMagnitude(1),
vp = (sbls->normal).Cross(up);
return (vp.Dot(axis) < 0);
up = axis.Cross(pto.Minus(ptc)).ScaledBy(da),
vp = up.Plus(axis.ScaledBy(dx));
return (vp.Dot(sbls->normal) > 0);
}
typedef struct {
@ -643,22 +644,19 @@ typedef struct {
// sketch must not contain the axis of revolution as a non-construction line for helix
void SShell::MakeFromHelicalRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis,
RgbaColor color, Group *group, double angles,
double anglef) {
double anglef, double dists, double distf) {
int i0 = surface.n; // number of pre-existing surfaces
SBezierLoop *sbl;
// for testing - hard code the axial distance, and number of sections.
// distance will need to be parameters in the future.
double dist = 0;
double dist = distf - dists;
int sections = fabs(anglef - angles) / (PI / 2) + 1;
if(sections > 99) {
sections = 99;
}
double wedge = (anglef - angles) / sections;
double dists = 0; // start distance
double distf = dist; // finish distance
if(CheckNormalAxisRelationship(sbls, pt, axis) ^ (wedge < 0)) {
if(CheckNormalAxisRelationship(sbls, pt, axis, anglef-angles, distf-dists)) {
swap(angles, anglef);
swap(dists, distf);
dist = -dist;
@ -821,7 +819,7 @@ void SShell::MakeFromRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis,
int i0 = surface.n; // number of pre-existing surfaces
SBezierLoop *sbl;
if(CheckNormalAxisRelationship(sbls, pt, axis)) {
if(CheckNormalAxisRelationship(sbls, pt, axis, 1.0, 0.0)) {
axis = axis.ScaledBy(-1);
}

View File

@ -382,11 +382,11 @@ public:
void MakeFromExtrusionOf(SBezierLoopSet *sbls, Vector t0, Vector t1,
RgbaColor color);
bool CheckNormalAxisRelationship(SBezierLoopSet *sbls, Vector pt, Vector axis);
bool CheckNormalAxisRelationship(SBezierLoopSet *sbls, Vector pt, Vector axis, double da, double dx);
void MakeFromRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis,
RgbaColor color, Group *group);
void MakeFromHelicalRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis, RgbaColor color,
Group *group, double angles, double anglef);
Group *group, double angles, double anglef, double dists, double distf);
void MakeFirstOrderRevolvedSurfaces(Vector pt, Vector axis, int i0);
void MakeFromUnionOf(SShell *a, SShell *b);
void MakeFromDifferenceOf(SShell *a, SShell *b);

View File

@ -304,11 +304,14 @@ void TextWindow::ShowGroupInfo() {
if(g->type == Group::Type::LATHE) {
Printf(true, " %Ftlathe plane sketch");
} else if(g->type == Group::Type::EXTRUDE || g->type == Group::Type::ROTATE ||
g->type == Group::Type::TRANSLATE || g->type == Group::Type::REVOLVE) {
g->type == Group::Type::TRANSLATE || g->type == Group::Type::REVOLVE ||
g->type == Group::Type::HELIX) {
if(g->type == Group::Type::EXTRUDE) {
s = "extrude plane sketch";
} else if(g->type == Group::Type::TRANSLATE) {
s = "translate original sketch";
} else if(g->type == Group::Type::HELIX) {
s = "create helical extrusion";
} else if(g->type == Group::Type::ROTATE) {
s = "rotate original sketch";
} else if(g->type == Group::Type::REVOLVE) {
@ -364,7 +367,8 @@ void TextWindow::ShowGroupInfo() {
Printf(false, "");
if(g->type == Group::Type::EXTRUDE || g->type == Group::Type::LATHE ||
g->type == Group::Type::REVOLVE || g->type == Group::Type::LINKED) {
g->type == Group::Type::REVOLVE || g->type == Group::Type::LINKED ||
g->type == Group::Type::HELIX) {
bool un = (g->meshCombine == Group::CombineAs::UNION);
bool diff = (g->meshCombine == Group::CombineAs::DIFFERENCE);
bool asy = (g->meshCombine == Group::CombineAs::ASSEMBLE);
@ -384,7 +388,7 @@ void TextWindow::ShowGroupInfo() {
(asy ? RADIO_TRUE : RADIO_FALSE));
if(g->type == Group::Type::EXTRUDE || g->type == Group::Type::LATHE ||
g->type == Group::Type::REVOLVE) {
g->type == Group::Type::REVOLVE || g->type == Group::Type::HELIX) {
Printf(false,
"%Bd %Ftcolor %E%Bz %Bd (%@, %@, %@) %f%D%Lf%Fl[change]%E",
&g->color,
@ -396,7 +400,8 @@ void TextWindow::ShowGroupInfo() {
}
if(g->type == Group::Type::EXTRUDE || g->type == Group::Type::LATHE ||
g->type == Group::Type::REVOLVE || g->type == Group::Type::LINKED) {
g->type == Group::Type::REVOLVE || g->type == Group::Type::LINKED ||
g->type == Group::Type::HELIX) {
Printf(false, " %Fd%f%LP%s suppress this group's solid model",
&TextWindow::ScreenChangeGroupOption,
g->suppress ? CHECK_TRUE : CHECK_FALSE);

View File

@ -125,6 +125,7 @@ enum class Command : uint32_t {
GROUP_3D,
GROUP_WRKPL,
GROUP_EXTRUDE,
GROUP_HELIX,
GROUP_LATHE,
GROUP_REVOLVE,
GROUP_ROT,