Allow removing spline points.

pull/4/head
EvilSpirit 2016-04-07 20:44:56 +06:00 committed by whitequark
parent 2d25bdb51f
commit 77d8291216
5 changed files with 86 additions and 5 deletions

View File

@ -8,8 +8,8 @@
#include "solvespace.h"
//-----------------------------------------------------------------------------
// Replace a point-coincident constraint on oldpt with that same constraint
// on newpt. Useful when splitting or tangent arcing.
// Replace constraints on oldpt with the same constraints on newpt.
// Useful when splitting, tangent arcing, or removing bezier points.
//-----------------------------------------------------------------------------
void GraphicsWindow::ReplacePointInConstraints(hEntity oldpt, hEntity newpt) {
int i;
@ -23,6 +23,27 @@ void GraphicsWindow::ReplacePointInConstraints(hEntity oldpt, hEntity newpt) {
}
}
//-----------------------------------------------------------------------------
// Remove constraints on hpt. Useful when removing bezier points.
//-----------------------------------------------------------------------------
void GraphicsWindow::RemoveConstraintsForPointBeingDeleted(hEntity hpt) {
SK.constraint.ClearTags();
for(int i = 0; i < SK.constraint.n; i++) {
Constraint *c = &(SK.constraint.elem[i]);
if(c->ptA.v == hpt.v || c->ptB.v == hpt.v) {
c->tag = 1;
(SS.deleted.constraints)++;
if(c->type != Constraint::POINTS_COINCIDENT &&
c->type != Constraint::HORIZONTAL &&
c->type != Constraint::VERTICAL)
{
(SS.deleted.nonTrivialConstraints)++;
}
}
}
SK.constraint.RemoveTagged();
}
//-----------------------------------------------------------------------------
// Let's say that A is coincident with B, and B is coincident with C. This
// implies that A is coincident with C; but if we delete B, then both
@ -67,9 +88,12 @@ void GraphicsWindow::FixConstraintsForPointBeingDeleted(hEntity hpt) {
c->tag = 1;
}
}
// These would get removed anyways when we regenerated, but do it now;
// that way subsequent calls of this function (if multiple coincident
// points are getting deleted) will work correctly.
// Remove constraints without waiting for regeneration; this way
// if another point takes the place of the deleted one (e.g. when
// removing control points of a bezier) the constraint doesn't
// spuriously move. Similarly, subsequent calls of this function
// (if multiple coincident points are getting deleted) will work
// correctly.
SK.constraint.RemoveTagged();
// If more than one point was constrained coincident with hpt, then

View File

@ -567,6 +567,18 @@ void GraphicsWindow::MouseRightUp(double x, double y) {
}
if(gs.comments > 0 || gs.points > 0) {
AddContextMenuItem("Snap to Grid", CMNU_SNAP_TO_GRID);
if(gs.points == 1) {
hRequest hr = gs.point[0].request();
if(hr.v != 0) {
Request *r = SK.GetRequest(hr);
int index = r->IndexOfPoint(gs.point[0]);
if((r->type == Request::CUBIC && (index > 1 && index < r->extraPoints + 2)) ||
r->type == Request::CUBIC_PERIODIC) {
AddContextMenuItem("Remove Spline Point", CMNU_REMOVE_SPLINE_PT);
}
}
}
}
if(gs.points == 1) {
@ -675,6 +687,36 @@ void GraphicsWindow::MouseRightUp(double x, double y) {
MenuEdit(MNU_SNAP_TO_GRID);
break;
case CMNU_REMOVE_SPLINE_PT: {
hRequest hr = gs.point[0].request();
Request *r = SK.GetRequest(hr);
int index = r->IndexOfPoint(gs.point[0]);
if(r->extraPoints == 0) oops();
SS.UndoRemember();
Entity *e = SK.GetEntity(r->h.entity(0));
// First, fix point-coincident constraints involving this point.
// Then, remove all other constraints, since they would otherwise
// jump to an adjacent one and mess up the bezier after generation.
FixConstraintsForPointBeingDeleted(e->point[index]);
RemoveConstraintsForPointBeingDeleted(e->point[index]);
for(int i = index; i < MAX_POINTS_IN_ENTITY - 1; i++) {
if(e->point[i + 1].v == 0) break;
Entity *p0 = SK.GetEntity(e->point[i]);
Entity *p1 = SK.GetEntity(e->point[i + 1]);
ReplacePointInConstraints(p1->h, p0->h);
p0->PointForceTo(p1->PointGetNum());
}
r->extraPoints--;
SS.MarkGroupDirtyByEntity(gs.point[0]);
SS.ScheduleGenerateAll();
ClearSelection();
break;
}
case CMNU_GROUP_INFO: {
hGroup hg;
if(gs.entities == 1) {

View File

@ -184,6 +184,18 @@ std::string Request::DescriptionString(void) {
return ssprintf("r%03x-%s", h.v, s);
}
int Request::IndexOfPoint(hEntity he) {
if(type == DATUM_POINT) {
return (he.v == h.entity(0).v) ? 0 : -1;
}
for(int i = 0; i < MAX_POINTS_IN_ENTITY; i++) {
if(he.v == h.entity(i + 1).v) {
return i;
}
}
return -1;
}
hParam Request::AddParam(IdList<Param,hParam> *param, hParam hp) {
Param pa = {};
pa.h = hp;

View File

@ -299,6 +299,7 @@ public:
void Generate(EntityList *entity, ParamList *param);
std::string DescriptionString(void);
int IndexOfPoint(hEntity he);
void Clear(void) {}
};

View File

@ -601,6 +601,7 @@ public:
hEntity SplitCircle(hEntity he, Vector pinter);
hEntity SplitCubic(hEntity he, Vector pinter);
void ReplacePointInConstraints(hEntity oldpt, hEntity newpt);
void RemoveConstraintsForPointBeingDeleted(hEntity hpt);
void FixConstraintsForRequestBeingDeleted(hRequest hr);
void FixConstraintsForPointBeingDeleted(hEntity hpt);
@ -678,6 +679,7 @@ public:
CMNU_OTHER_ANGLE = 0x131,
CMNU_DEL_COINCIDENT = 0x132,
CMNU_SNAP_TO_GRID = 0x140,
CMNU_REMOVE_SPLINE_PT = 0x141,
CMNU_FIRST_STYLE = 0x40000000
};
void ContextMenuListStyles(void);