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 sketch features:
* New group, revolve. * New groups, revolution and helical extrusion.
* Extrude, lathe, translate and rotate groups can use the "assembly" * Extrude, lathe, translate and rotate groups can use the "assembly"
boolean operation, to increase performance. boolean operation, to increase performance.
* The solid model of extrude and lathe groups can be suppressed, * 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_TRANS:
case Type::POINT_N_ROT_TRANS: case Type::POINT_N_ROT_TRANS:
case Type::POINT_N_ROT_AA: case Type::POINT_N_ROT_AA:
case Type::POINT_N_ROT_AXIS_TRANS:
case Type::POINT_IN_3D: case Type::POINT_IN_3D:
case Type::POINT_IN_2D: case Type::POINT_IN_2D:
refs->push_back(PointGetNum()); refs->push_back(PointGetNum());
@ -502,6 +503,7 @@ void Entity::Draw(DrawAs how, Canvas *canvas) {
case Type::POINT_N_TRANS: case Type::POINT_N_TRANS:
case Type::POINT_N_ROT_TRANS: case Type::POINT_N_ROT_TRANS:
case Type::POINT_N_ROT_AA: case Type::POINT_N_ROT_AA:
case Type::POINT_N_ROT_AXIS_TRANS:
case Type::POINT_IN_3D: case Type::POINT_IN_3D:
case Type::POINT_IN_2D: { case Type::POINT_IN_2D: {
if(how == DrawAs::HIDDEN) return; if(how == DrawAs::HIDDEN) return;

View File

@ -245,6 +245,7 @@ bool EntityBase::IsPoint() const {
case Type::POINT_N_TRANS: case Type::POINT_N_TRANS:
case Type::POINT_N_ROT_TRANS: case Type::POINT_N_ROT_TRANS:
case Type::POINT_N_ROT_AA: case Type::POINT_N_ROT_AA:
case Type::POINT_N_ROT_AXIS_TRANS:
return true; return true;
default: default:
@ -454,10 +455,38 @@ void EntityBase::PointForceTo(Vector p) {
// in order to avoid jumps when you cross from +pi to -pi // in order to avoid jumps when you cross from +pi to -pi
while(dtheta < -PI) dtheta += 2*PI; while(dtheta < -PI) dtheta += 2*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); SK.GetParam(param[3])->val = (thetai + dtheta)/(timesApplied*2);
break; 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: case Type::POINT_N_COPY:
// Nothing to do; it's a static copy // Nothing to do; it's a static copy
break; break;
@ -506,6 +535,17 @@ Vector EntityBase::PointGetNum() const {
break; 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: case Type::POINT_N_COPY:
p = numPoint; p = numPoint;
break; break;
@ -555,6 +595,18 @@ ExprVector EntityBase::PointGetExprs() const {
r = orig.Plus(trans); r = orig.Plus(trans);
break; 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: case Type::POINT_N_COPY:
r = ExprVector::From(numPoint); r = ExprVector::From(numPoint);
break; break;
@ -633,7 +685,7 @@ ExprQuaternion EntityBase::GetAxisAngleQuaternionExprs(int param0) const {
Quaternion EntityBase::PointGetQuaternion() const { Quaternion EntityBase::PointGetQuaternion() const {
Quaternion q; 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); q = GetAxisAngleQuaternion(3);
} else if(type == Type::POINT_N_ROT_TRANS) { } else if(type == Type::POINT_N_ROT_TRANS) {
q = Quaternion::From(param[3], param[4], param[5], param[6]); 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::CIRCLE:
case Type::ARC_OF_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. // are parallel and the mid point is in the plane.
Vector n = Normal()->NormalN(); Vector n = Normal()->NormalN();
if (!norm.Equals(n) && !norm.Equals(n.Negated())) return false; if (!norm.Equals(n) && !norm.Equals(n.Negated())) return false;

View File

@ -445,6 +445,7 @@ void SolveSpaceUI::MarkDraggedParams() {
switch(pt->type) { switch(pt->type) {
case Entity::Type::POINT_N_TRANS: case Entity::Type::POINT_N_TRANS:
case Entity::Type::POINT_IN_3D: 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[0]));
sys.dragged.Add(&(pt->param[1])); sys.dragged.Add(&(pt->param[1]));
sys.dragged.Add(&(pt->param[2])); 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, N_("Step &Rotating"), Command::GROUP_ROT, S|'r', KN, mGrp },
{ 1, NULL, Command::NONE, 0, KN, NULL }, { 1, NULL, Command::NONE, 0, KN, NULL },
{ 1, N_("E&xtrude"), Command::GROUP_EXTRUDE, S|'x', KN, mGrp }, { 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_("&Lathe"), Command::GROUP_LATHE, S|'l', KN, mGrp },
{ 1, N_("Re&volve"), Command::GROUP_REVOLVE, S|'v', KN, mGrp }, { 1, N_("Re&volve"), Command::GROUP_REVOLVE, S|'v', KN, mGrp },
{ 1, NULL, Command::NONE, 0, KN, NULL }, { 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"); g.name = C_("group-name", "revolve");
break; 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: { case Command::GROUP_ROT: {
if(gs.points == 1 && gs.n == 1 && SS.GW.LockedInWorkplane()) { if(gs.points == 1 && gs.n == 1 && SS.GW.LockedInWorkplane()) {
g.predef.origin = gs.point[0]; g.predef.origin = gs.point[0];
@ -368,7 +392,7 @@ std::string Group::DescriptionString() {
void Group::Activate() { void Group::Activate() {
if(type == Type::EXTRUDE || type == Type::LINKED || type == Type::LATHE || 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; SS.GW.showFaces = true;
} else { } else {
SS.GW.showFaces = false; SS.GW.showFaces = false;
@ -460,11 +484,11 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
// adds entities, which may cause a realloc. // adds entities, which may cause a realloc.
CopyEntity(entity, SK.GetEntity(he), ai, REMAP_BOTTOM, CopyEntity(entity, SK.GetEntity(he), ai, REMAP_BOTTOM,
h.param(0), h.param(1), h.param(2), 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); CopyAs::N_TRANS);
CopyEntity(entity, SK.GetEntity(he), af, REMAP_TOP, CopyEntity(entity, SK.GetEntity(he), af, REMAP_TOP,
h.param(0), h.param(1), h.param(2), 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); CopyAs::N_TRANS);
MakeExtrusionLines(entity, he); MakeExtrusionLines(entity, he);
} }
@ -492,17 +516,17 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
// adds entities, which may cause a realloc. // adds entities, which may cause a realloc.
CopyEntity(entity, SK.GetEntity(predef.origin), 0, ai, 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, NO_PARAM, NO_PARAM, NO_PARAM,
CopyAs::NUMERIC); CopyAs::NUMERIC);
CopyEntity(entity, SK.GetEntity(he), 0, REMAP_LATHE_START, 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, NO_PARAM, NO_PARAM, NO_PARAM,
CopyAs::NUMERIC); CopyAs::NUMERIC);
CopyEntity(entity, SK.GetEntity(he), 0, REMAP_LATHE_END, 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, NO_PARAM, NO_PARAM, NO_PARAM,
CopyAs::NUMERIC); CopyAs::NUMERIC);
MakeLatheCircles(entity, param, he, axis_pos, axis_dir, ai); 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(5), axis_dir.y);
AddParam(param, h.param(6), axis_dir.z); AddParam(param, h.param(6), axis_dir.z);
int n = 2;
int ai = 1; int ai = 1;
for(i = 0; i < entity->n; i++) { for(i = 0; i < entity->n; i++) {
@ -539,17 +562,17 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
hEntity he = e->h; hEntity he = e->h;
CopyEntity(entity, SK.GetEntity(predef.origin), 0, ai, NO_PARAM, NO_PARAM, 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++) { for(a = 0; a < 2; a++) {
if(e->group != opA) if(e->group != opA)
continue; continue;
e->CalculateNumerical(false); e->CalculateNumerical(false);
CopyEntity(entity, e, a * 2 - (subtype == Subtype::ONE_SIDED ? 0 : (n - 1)), CopyEntity(entity, e, a * 2 - (subtype == Subtype::ONE_SIDED ? 0 : 1),
(a == (n - 1)) ? REMAP_LATHE_END : REMAP_LATHE_START, h.param(0), (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(1), h.param(2), h.param(3), h.param(4), h.param(5),
h.param(6), CopyAs::N_ROT_AA); h.param(6), NO_PARAM, CopyAs::N_ROT_AA);
} }
// Arcs are not generated for revolve groups, for now, because our current arc // 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. // 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; 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: { case Type::TRANSLATE: {
// inherit meshCombine from source group // inherit meshCombine from source group
Group *srcg = SK.GetGroup(opA); 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*2 - (subtype == Subtype::ONE_SIDED ? 0 : (n-1)),
(a == (n - 1)) ? REMAP_LAST : a, (a == (n - 1)) ? REMAP_LAST : a,
h.param(0), h.param(1), h.param(2), 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); CopyAs::N_TRANS);
} }
} }
@ -620,7 +700,7 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
a*2 - (subtype == Subtype::ONE_SIDED ? 0 : (n-1)), a*2 - (subtype == Subtype::ONE_SIDED ? 0 : (n-1)),
(a == (n - 1)) ? REMAP_LAST : a, (a == (n - 1)) ? REMAP_LAST : a,
h.param(0), h.param(1), h.param(2), 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); CopyAs::N_ROT_AA);
} }
} }
@ -641,7 +721,7 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
Entity *ie = &(impEntity.elem[i]); Entity *ie = &(impEntity.elem[i]);
CopyEntity(entity, ie, 0, 0, CopyEntity(entity, ie, 0, 0,
h.param(0), h.param(1), h.param(2), 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); CopyAs::N_ROT_TRANS);
} }
return; return;
@ -670,7 +750,7 @@ void Group::GenerateEquations(IdList<Equation,hEquation> *l) {
Expr::From(h.param(5)), Expr::From(h.param(5)),
Expr::From(h.param(6)) }; Expr::From(h.param(6)) };
AddEq(l, (q.Magnitude())->Minus(Expr::From(1)), 0); 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 // The axis and center of rotation are specified numerically
#define EC(x) (Expr::From(x)) #define EC(x) (Expr::From(x))
#define EP(x) (Expr::From(h.param(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, void Group::CopyEntity(IdList<Entity,hEntity> *el,
Entity *ep, int timesApplied, int remap, Entity *ep, int timesApplied, int remap,
hParam dx, hParam dy, hParam dz, 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) CopyAs as)
{ {
Entity en = {}; Entity en = {};
@ -891,6 +971,7 @@ void Group::CopyEntity(IdList<Entity,hEntity> *el,
case Entity::Type::POINT_N_TRANS: case Entity::Type::POINT_N_TRANS:
case Entity::Type::POINT_N_ROT_TRANS: case Entity::Type::POINT_N_ROT_TRANS:
case Entity::Type::POINT_N_ROT_AA: 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_3D:
case Entity::Type::POINT_IN_2D: case Entity::Type::POINT_IN_2D:
if(as == CopyAs::N_TRANS) { if(as == CopyAs::N_TRANS) {
@ -903,6 +984,8 @@ void Group::CopyEntity(IdList<Entity,hEntity> *el,
} else { } else {
if(as == CopyAs::N_ROT_AA) { if(as == CopyAs::N_ROT_AA) {
en.type = Entity::Type::POINT_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 { } else {
en.type = Entity::Type::POINT_N_ROT_TRANS; 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[4] = qvx;
en.param[5] = qvy; en.param[5] = qvy;
en.param[6] = qvz; en.param[6] = qvz;
if (as == CopyAs::N_ROT_AXIS_TRANS) {
en.param[7] = dist;
}
} }
en.numPoint = (ep->actPoint).ScaledBy(scale); en.numPoint = (ep->actPoint).ScaledBy(scale);
break; break;
@ -924,8 +1010,8 @@ void Group::CopyEntity(IdList<Entity,hEntity> *el,
case Entity::Type::NORMAL_IN_2D: case Entity::Type::NORMAL_IN_2D:
if(as == CopyAs::N_TRANS || as == CopyAs::NUMERIC) { if(as == CopyAs::N_TRANS || as == CopyAs::NUMERIC) {
en.type = Entity::Type::NORMAL_N_COPY; en.type = Entity::Type::NORMAL_N_COPY;
} else { } else { // N_ROT_AXIS_TRANS probably doesn't warrant a new entity Type
if(as == CopyAs::N_ROT_AA) { if(as == CopyAs::N_ROT_AA || as == CopyAs::N_ROT_AXIS_TRANS) {
en.type = Entity::Type::NORMAL_N_ROT_AA; en.type = Entity::Type::NORMAL_N_ROT_AA;
} else { } else {
en.type = Entity::Type::NORMAL_N_ROT; en.type = Entity::Type::NORMAL_N_ROT;
@ -960,7 +1046,7 @@ void Group::CopyEntity(IdList<Entity,hEntity> *el,
} else if (as == CopyAs::NUMERIC) { } else if (as == CopyAs::NUMERIC) {
en.type = Entity::Type::FACE_NORMAL_PT; en.type = Entity::Type::FACE_NORMAL_PT;
} else { } 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; en.type = Entity::Type::FACE_N_ROT_AA;
} else { } else {
en.type = Entity::Type::FACE_N_ROT_TRANS; en.type = Entity::Type::FACE_N_ROT_TRANS;

View File

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

View File

@ -151,6 +151,7 @@ public:
N_TRANS, N_TRANS,
N_ROT_AA, N_ROT_AA,
N_ROT_TRANS, N_ROT_TRANS,
N_ROT_AXIS_TRANS,
}; };
enum class Type : uint32_t { enum class Type : uint32_t {
@ -159,6 +160,7 @@ public:
EXTRUDE = 5100, EXTRUDE = 5100,
LATHE = 5101, LATHE = 5101,
REVOLVE = 5102, REVOLVE = 5102,
HELIX = 5103,
ROTATE = 5200, ROTATE = 5200,
TRANSLATE = 5201, TRANSLATE = 5201,
LINKED = 5300 LINKED = 5300
@ -286,7 +288,7 @@ public:
void CopyEntity(EntityList *el, void CopyEntity(EntityList *el,
Entity *ep, int timesApplied, int remap, Entity *ep, int timesApplied, int remap,
hParam dx, hParam dy, hParam dz, 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); CopyAs as);
void AddEq(IdList<Equation,hEquation> *l, Expr *expr, int index); void AddEq(IdList<Equation,hEquation> *l, Expr *expr, int index);
@ -387,6 +389,7 @@ public:
POINT_N_ROT_TRANS = 2011, POINT_N_ROT_TRANS = 2011,
POINT_N_COPY = 2012, POINT_N_COPY = 2012,
POINT_N_ROT_AA = 2013, POINT_N_ROT_AA = 2013,
POINT_N_ROT_AXIS_TRANS = 2014,
NORMAL_IN_3D = 3000, NORMAL_IN_3D = 3000,
NORMAL_IN_2D = 3001, NORMAL_IN_2D = 3001,
@ -426,7 +429,7 @@ public:
hEntity distance; hEntity distance;
// The only types that have their own params are points, normals, // The only types that have their own params are points, normals,
// and directions. // and directions.
hParam param[7]; hParam param[8];
// Transformed points/normals/distances have their numerical base // Transformed points/normals/distances have their numerical base
Vector numPoint; 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) bool SShell::CheckNormalAxisRelationship(SBezierLoopSet *sbls, Vector pt, Vector axis, double da, double dx)
// Check that the direction of revolution ends up parallel to the normal of // 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. // the sketch, on the side of the axis where the sketch is.
{ {
SBezierLoop *sbl; SBezierLoop *sbl;
@ -631,9 +631,10 @@ bool SShell::CheckNormalAxisRelationship(SBezierLoopSet *sbls, Vector pt, Vector
} }
} }
Vector ptc = pto.ClosestPointOnLine(pt, axis), Vector ptc = pto.ClosestPointOnLine(pt, axis),
up = (pto.Minus(ptc)).WithMagnitude(1), up = axis.Cross(pto.Minus(ptc)).ScaledBy(da),
vp = (sbls->normal).Cross(up); vp = up.Plus(axis.ScaledBy(dx));
return (vp.Dot(axis) < 0);
return (vp.Dot(sbls->normal) > 0);
} }
typedef struct { typedef struct {
@ -643,22 +644,19 @@ typedef struct {
// sketch must not contain the axis of revolution as a non-construction line for helix // sketch must not contain the axis of revolution as a non-construction line for helix
void SShell::MakeFromHelicalRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis, void SShell::MakeFromHelicalRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis,
RgbaColor color, Group *group, double angles, RgbaColor color, Group *group, double angles,
double anglef) { double anglef, double dists, double distf) {
int i0 = surface.n; // number of pre-existing surfaces int i0 = surface.n; // number of pre-existing surfaces
SBezierLoop *sbl; SBezierLoop *sbl;
// for testing - hard code the axial distance, and number of sections. // for testing - hard code the axial distance, and number of sections.
// distance will need to be parameters in the future. // distance will need to be parameters in the future.
double dist = 0; double dist = distf - dists;
int sections = fabs(anglef - angles) / (PI / 2) + 1; int sections = fabs(anglef - angles) / (PI / 2) + 1;
if(sections > 99) { if(sections > 99) {
sections = 99; sections = 99;
} }
double wedge = (anglef - angles) / sections; double wedge = (anglef - angles) / sections;
double dists = 0; // start distance if(CheckNormalAxisRelationship(sbls, pt, axis, anglef-angles, distf-dists)) {
double distf = dist; // finish distance
if(CheckNormalAxisRelationship(sbls, pt, axis) ^ (wedge < 0)) {
swap(angles, anglef); swap(angles, anglef);
swap(dists, distf); swap(dists, distf);
dist = -dist; dist = -dist;
@ -821,7 +819,7 @@ void SShell::MakeFromRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis,
int i0 = surface.n; // number of pre-existing surfaces int i0 = surface.n; // number of pre-existing surfaces
SBezierLoop *sbl; SBezierLoop *sbl;
if(CheckNormalAxisRelationship(sbls, pt, axis)) { if(CheckNormalAxisRelationship(sbls, pt, axis, 1.0, 0.0)) {
axis = axis.ScaledBy(-1); axis = axis.ScaledBy(-1);
} }

View File

@ -382,11 +382,11 @@ public:
void MakeFromExtrusionOf(SBezierLoopSet *sbls, Vector t0, Vector t1, void MakeFromExtrusionOf(SBezierLoopSet *sbls, Vector t0, Vector t1,
RgbaColor color); 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, void MakeFromRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis,
RgbaColor color, Group *group); RgbaColor color, Group *group);
void MakeFromHelicalRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis, RgbaColor color, 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 MakeFirstOrderRevolvedSurfaces(Vector pt, Vector axis, int i0);
void MakeFromUnionOf(SShell *a, SShell *b); void MakeFromUnionOf(SShell *a, SShell *b);
void MakeFromDifferenceOf(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) { if(g->type == Group::Type::LATHE) {
Printf(true, " %Ftlathe plane sketch"); Printf(true, " %Ftlathe plane sketch");
} else if(g->type == Group::Type::EXTRUDE || g->type == Group::Type::ROTATE || } 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) { if(g->type == Group::Type::EXTRUDE) {
s = "extrude plane sketch"; s = "extrude plane sketch";
} else if(g->type == Group::Type::TRANSLATE) { } else if(g->type == Group::Type::TRANSLATE) {
s = "translate original sketch"; s = "translate original sketch";
} else if(g->type == Group::Type::HELIX) {
s = "create helical extrusion";
} else if(g->type == Group::Type::ROTATE) { } else if(g->type == Group::Type::ROTATE) {
s = "rotate original sketch"; s = "rotate original sketch";
} else if(g->type == Group::Type::REVOLVE) { } else if(g->type == Group::Type::REVOLVE) {
@ -364,7 +367,8 @@ void TextWindow::ShowGroupInfo() {
Printf(false, ""); Printf(false, "");
if(g->type == Group::Type::EXTRUDE || g->type == Group::Type::LATHE || 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 un = (g->meshCombine == Group::CombineAs::UNION);
bool diff = (g->meshCombine == Group::CombineAs::DIFFERENCE); bool diff = (g->meshCombine == Group::CombineAs::DIFFERENCE);
bool asy = (g->meshCombine == Group::CombineAs::ASSEMBLE); bool asy = (g->meshCombine == Group::CombineAs::ASSEMBLE);
@ -384,7 +388,7 @@ void TextWindow::ShowGroupInfo() {
(asy ? RADIO_TRUE : RADIO_FALSE)); (asy ? RADIO_TRUE : RADIO_FALSE));
if(g->type == Group::Type::EXTRUDE || g->type == Group::Type::LATHE || 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, Printf(false,
"%Bd %Ftcolor %E%Bz %Bd (%@, %@, %@) %f%D%Lf%Fl[change]%E", "%Bd %Ftcolor %E%Bz %Bd (%@, %@, %@) %f%D%Lf%Fl[change]%E",
&g->color, &g->color,
@ -396,7 +400,8 @@ void TextWindow::ShowGroupInfo() {
} }
if(g->type == Group::Type::EXTRUDE || g->type == Group::Type::LATHE || 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", Printf(false, " %Fd%f%LP%s suppress this group's solid model",
&TextWindow::ScreenChangeGroupOption, &TextWindow::ScreenChangeGroupOption,
g->suppress ? CHECK_TRUE : CHECK_FALSE); g->suppress ? CHECK_TRUE : CHECK_FALSE);

View File

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