Skip to content

Commit

Permalink
Let tangent arc modify the original entities.
Browse files Browse the repository at this point in the history
Modifying the original entities instead of deleting them, retains the
original associated constraints. This makes creating rounded rectangles
a lot easier.
  • Loading branch information
bcmpinc authored and whitequark committed Feb 11, 2019
1 parent c0678d7 commit e69478e
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 49 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -88,6 +88,8 @@ Bugs fixed:
* A step rotate/translate group using a group forced to triangle mesh
as a source group also gets forced to triangle mesh.
* Paste Transformed with a negative scale does not invert arcs.
* The tangent arc now modifies the original entities instead of deleting
them, such that their constraints are retained.

2.x
---
Expand Down
108 changes: 66 additions & 42 deletions src/modify.cpp
Expand Up @@ -161,46 +161,65 @@ Vector GraphicsWindow::ParametricCurve::TangentAt(double t) {
return t;
}
}
hRequest GraphicsWindow::ParametricCurve::CreateRequestTrimmedTo(double t,
bool extraConstraints, hEntity orig, hEntity arc, bool arcFinish)
/** Changes or copies the given entity and connects it to the arc.
* \param t Where on this parametric curve does it connect to the arc.
* \param reuseOrig Should the original entity be modified
* \param orig The original entity.
* \param arc The arc that will be connected to.
* \param arcFinish Whether to connect to the end point of the arc.
* \param pointf When changing the original entity, whether the end point should be modified.
*/
void GraphicsWindow::ParametricCurve::CreateRequestTrimmedTo(double t,
bool reuseOrig, hEntity orig, hEntity arc, bool arcFinish, bool pointf)
{
hRequest hr;
Entity *e;
if(isLine) {
hr = SS.GW.AddRequest(Request::Type::LINE_SEGMENT, /*rememberForUndo=*/false),
e = SK.GetEntity(hr.entity(0));
SK.GetEntity(e->point[0])->PointForceTo(PointAt(t));
SK.GetEntity(e->point[1])->PointForceTo(PointAt(1));
ConstrainPointIfCoincident(e->point[0]);
ConstrainPointIfCoincident(e->point[1]);
if(extraConstraints) {
if (reuseOrig) {
e = SK.GetEntity(orig);
int i = pointf ? 1 : 0;
SK.GetEntity(e->point[i])->PointForceTo(PointAt(t));
ConstrainPointIfCoincident(e->point[i]);
} else {
hr = SS.GW.AddRequest(Request::Type::LINE_SEGMENT, /*rememberForUndo=*/false),
e = SK.GetEntity(hr.entity(0));
SK.GetEntity(e->point[0])->PointForceTo(PointAt(t));
SK.GetEntity(e->point[1])->PointForceTo(PointAt(1));
ConstrainPointIfCoincident(e->point[0]);
ConstrainPointIfCoincident(e->point[1]);
Constraint::Constrain(Constraint::Type::PT_ON_LINE,
hr.entity(1), Entity::NO_ENTITY, orig);
}
Constraint::Constrain(Constraint::Type::ARC_LINE_TANGENT,
Entity::NO_ENTITY, Entity::NO_ENTITY,
arc, e->h, /*other=*/arcFinish, /*other2=*/false);
} else {
hr = SS.GW.AddRequest(Request::Type::ARC_OF_CIRCLE, /*rememberForUndo=*/false),
e = SK.GetEntity(hr.entity(0));
SK.GetEntity(e->point[0])->PointForceTo(p0);
if(dtheta > 0) {
SK.GetEntity(e->point[1])->PointForceTo(PointAt(t));
SK.GetEntity(e->point[2])->PointForceTo(PointAt(1));
if (reuseOrig) {
e = SK.GetEntity(orig);
int i = pointf ? 2 : 1;
SK.GetEntity(e->point[i])->PointForceTo(PointAt(t));
ConstrainPointIfCoincident(e->point[i]);
} else {
SK.GetEntity(e->point[2])->PointForceTo(PointAt(t));
SK.GetEntity(e->point[1])->PointForceTo(PointAt(1));
hr = SS.GW.AddRequest(Request::Type::ARC_OF_CIRCLE, /*rememberForUndo=*/false),
e = SK.GetEntity(hr.entity(0));
SK.GetEntity(e->point[0])->PointForceTo(p0);
if(dtheta > 0) {
SK.GetEntity(e->point[1])->PointForceTo(PointAt(t));
SK.GetEntity(e->point[2])->PointForceTo(PointAt(1));
} else {
SK.GetEntity(e->point[2])->PointForceTo(PointAt(t));
SK.GetEntity(e->point[1])->PointForceTo(PointAt(1));
}
ConstrainPointIfCoincident(e->point[0]);
ConstrainPointIfCoincident(e->point[1]);
ConstrainPointIfCoincident(e->point[2]);
}
ConstrainPointIfCoincident(e->point[0]);
ConstrainPointIfCoincident(e->point[1]);
ConstrainPointIfCoincident(e->point[2]);
// The tangency constraint alone is enough to fully constrain it,
// so there's no need for more.
Constraint::Constrain(Constraint::Type::CURVE_CURVE_TANGENT,
Entity::NO_ENTITY, Entity::NO_ENTITY,
arc, e->h, /*other=*/arcFinish, /*other2=*/(dtheta < 0));
}
return hr;
}

//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -388,6 +407,27 @@ void GraphicsWindow::MakeTangentArc() {

SS.UndoRemember();

if (SS.tangentArcModify) {
// Delete the coincident constraint for the removed point.
SK.constraint.ClearTags();
for(i = 0; i < SK.constraint.n; i++) {
Constraint *cs = &(SK.constraint.elem[i]);
if(cs->group.v != activeGroup.v) continue;
if(cs->workplane.v != ActiveWorkplane().v) continue;
if(cs->type != Constraint::Type::POINTS_COINCIDENT) continue;
if (SK.GetEntity(cs->ptA)->PointGetNum().Equals(pshared)) {
cs->tag = 1;
}
}
SK.constraint.RemoveTagged();
} else {
// Make the original entities construction, or delete them
// entirely, according to user preference.
SK.GetRequest(hreq[0])->construction = true;
SK.GetRequest(hreq[1])->construction = true;
}

// Create and position the new tangent arc.
hRequest harc = AddRequest(Request::Type::ARC_OF_CIRCLE, /*rememberForUndo=*/false);
Entity *earc = SK.GetEntity(harc.entity(0));
hEntity hearc = earc->h;
Expand All @@ -398,27 +438,11 @@ void GraphicsWindow::MakeTangentArc() {

earc = NULL;

pc[0].CreateRequestTrimmedTo(t[0], !SS.tangentArcDeleteOld,
hent[0], hearc, /*arcFinish=*/(b == 1));
pc[1].CreateRequestTrimmedTo(t[1], !SS.tangentArcDeleteOld,
hent[1], hearc, /*arcFinish=*/(a == 1));

// Now either make the original entities construction, or delete them
// entirely, according to user preference.
Request *re;
SK.request.ClearTags();
for(re = SK.request.First(); re; re = SK.request.NextAfter(re)) {
if(re->h.v == hreq[0].v || re->h.v == hreq[1].v) {
if(SS.tangentArcDeleteOld) {
re->tag = 1;
} else {
re->construction = true;
}
}
}
if(SS.tangentArcDeleteOld) {
DeleteTaggedRequests();
}
// Modify or duplicate the original entities and connect them to the tangent arc.
pc[0].CreateRequestTrimmedTo(t[0], SS.tangentArcModify,
hent[0], hearc, /*arcFinish=*/(b == 1), pointf[0]);
pc[1].CreateRequestTrimmedTo(t[1], SS.tangentArcModify,
hent[1], hearc, /*arcFinish=*/(a == 1), pointf[1]);
}

hEntity GraphicsWindow::SplitLine(hEntity he, Vector pinter) {
Expand Down
2 changes: 1 addition & 1 deletion src/solvespace.h
Expand Up @@ -638,7 +638,7 @@ class SolveSpaceUI {
// as special requests.
double tangentArcRadius;
bool tangentArcManual;
bool tangentArcDeleteOld;
bool tangentArcModify;

// The platform-dependent code calls this before entering the msg loop
void Init();
Expand Down
6 changes: 3 additions & 3 deletions src/textscreens.cpp
Expand Up @@ -643,7 +643,7 @@ void TextWindow::ScreenChangeTangentArc(int link, uint32_t v) {
}

case 'a': SS.tangentArcManual = !SS.tangentArcManual; break;
case 'd': SS.tangentArcDeleteOld = !SS.tangentArcDeleteOld; break;
case 'm': SS.tangentArcModify = !SS.tangentArcModify; break;
}
}
void TextWindow::ShowTangentArc() {
Expand All @@ -662,9 +662,9 @@ void TextWindow::ShowTangentArc() {
Printf(false, " %Fd%f%La%s choose radius automatically%E",
&ScreenChangeTangentArc,
!SS.tangentArcManual ? CHECK_TRUE : CHECK_FALSE);
Printf(false, " %Fd%f%Ld%s delete original entities afterward%E",
Printf(false, " %Fd%f%Lm%s modify original entities%E",
&ScreenChangeTangentArc,
SS.tangentArcDeleteOld ? CHECK_TRUE : CHECK_FALSE);
SS.tangentArcModify ? CHECK_TRUE : CHECK_FALSE);

Printf(false, "");
Printf(false, "To create a tangent arc at a point,");
Expand Down
7 changes: 4 additions & 3 deletions src/ui.h
Expand Up @@ -668,8 +668,8 @@ class GraphicsWindow {
Vector TangentAt(double t);
double LengthForAuto();

hRequest CreateRequestTrimmedTo(double t, bool extraConstraints,
hEntity orig, hEntity arc, bool arcFinish);
void CreateRequestTrimmedTo(double t, bool reuseOrig,
hEntity orig, hEntity arc, bool arcFinish, bool pointf);
void ConstrainPointIfCoincident(hEntity hpt);
};
void MakeTangentArc();
Expand Down Expand Up @@ -718,6 +718,7 @@ class GraphicsWindow {
void HitTestMakeSelection(Point2d mp);
void ClearSelection();
void ClearNonexistentSelectionItems();
/// This structure is filled by a call to GroupSelection().
struct {
std::vector<hEntity> point;
std::vector<hEntity> entity;
Expand All @@ -740,7 +741,7 @@ class GraphicsWindow {
int stylables;
int constraintLabels;
int withEndpoints;
int n;
int n; ///< Number of selected items
} gs;
void GroupSelection();
bool IsSelected(Selection *s);
Expand Down

0 comments on commit e69478e

Please sign in to comment.