Split cubic splines and periodic splines too; which is a pain,

because it can't be C2 continuous after splitting (since I'm
doing uniform splines only, and the parametrization changes). So
just knock everything down to cubic Beziers.

Also draw lines to indicate angle and origin when Ctrl+dragging to
rotate in plane of screen.

[git-p4: depot-paths = "//depot/solvespace/": change = 2075]
This commit is contained in:
Jonathan Westhues 2009-11-09 19:57:24 -08:00
parent c79ca083c1
commit 4cfe7eea64
6 changed files with 111 additions and 44 deletions

View File

@ -261,10 +261,10 @@ void GraphicsWindow::GroupSelection(void) {
// And some aux counts too
switch(e->type) {
case Entity::WORKPLANE: (gs.workplanes)++; break;
case Entity::LINE_SEGMENT: (gs.lineSegments)++; break;
case Entity::CUBIC: (gs.cubics)++; break;
// but don't count periodic cubics
case Entity::WORKPLANE: (gs.workplanes)++; break;
case Entity::LINE_SEGMENT: (gs.lineSegments)++; break;
case Entity::CUBIC: (gs.cubics)++; break;
case Entity::CUBIC_PERIODIC: (gs.periodicCubics)++; break;
case Entity::ARC_OF_CIRCLE:
(gs.circlesOrArcs)++;
@ -727,6 +727,15 @@ nogrid:;
glEnd();
}
if(pending.drawLine) {
glLineWidth(1);
glxLockColorTo(Style::Color(Style::DATUM));
glBegin(GL_LINES);
glxVertex3v(pending.lnA);
glxVertex3v(pending.lnB);
glEnd();
}
// And finally the toolbar.
if(SS.showToolbar) {
ToolbarDraw();

View File

@ -39,6 +39,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 1, "Cu&t\tCtrl+X", MNU_CUT, 'X'|C, mEdit },
{ 1, "&Copy\tCtrl+C", MNU_COPY, 'C'|C, mEdit },
{ 1, "&Paste\tCtrl+V", MNU_PASTE, 'V'|C, mEdit },
{ 1, "Paste &Transformed...\tCtrl+T", MNU_PASTE_TRANSFORM,'T'|C, mEdit },
{ 1, "&Delete\tDel", MNU_DELETE, 127, mEdit },
{ 1, NULL, 0, NULL },
{ 1, "Select Edge Cha&in\tCtrl+I", MNU_SELECT_CHAIN, 'I'|C, mEdit },

View File

@ -16,7 +16,6 @@ void GraphicsWindow::ReplacePointInConstraints(hEntity oldpt, hEntity newpt) {
}
}
void GraphicsWindow::FixConstraintsForRequestBeingDeleted(hRequest hr) {
Request *r = SK.GetRequest(hr);
if(r->group.v != SS.GW.activeGroup.v) return;
@ -220,8 +219,6 @@ hEntity GraphicsWindow::SplitLine(hEntity he, Vector pinter) {
Vector p0 = SK.GetEntity(hep0)->PointGetNum(),
p1 = SK.GetEntity(hep1)->PointGetNum();
SS.UndoRemember();
// Add the two line segments this one gets split into.
hRequest r0i = AddRequest(Request::LINE_SEGMENT, false),
ri1 = AddRequest(Request::LINE_SEGMENT, false);
@ -242,8 +239,6 @@ hEntity GraphicsWindow::SplitLine(hEntity he, Vector pinter) {
}
hEntity GraphicsWindow::SplitCircle(hEntity he, Vector pinter) {
SS.UndoRemember();
Entity *circle = SK.GetEntity(he);
if(circle->type == Entity::CIRCLE) {
// Start with an unbroken circle, split it into a 360 degree arc.
@ -294,44 +289,67 @@ hEntity GraphicsWindow::SplitCircle(hEntity he, Vector pinter) {
hEntity GraphicsWindow::SplitCubic(hEntity he, Vector pinter) {
// Save the original endpoints, since we're about to delete this entity.
Entity *e01 = SK.GetEntity(he);
SBezierList sbl;
ZERO(&sbl);
e01->GenerateBezierCurves(&sbl);
hEntity hep0 = e01->point[0],
hep1 = e01->point[1],
hep2 = e01->point[2],
hep3 = e01->point[3];
Vector p0 = SK.GetEntity(hep0)->PointGetNum(),
p1 = SK.GetEntity(hep1)->PointGetNum(),
p2 = SK.GetEntity(hep2)->PointGetNum(),
p3 = SK.GetEntity(hep3)->PointGetNum();
hep1 = e01->point[3+e01->extraPoints],
hep0n = Entity::NO_ENTITY, // the new start point
hep1n = Entity::NO_ENTITY, // the new finish point
hepin = Entity::NO_ENTITY; // the intersection point
SS.UndoRemember();
SBezier b0i, bi1, b01 = SBezier::From(p0, p1, p2, p3);
// The curve may consist of multiple cubic segments. So find which one
// contains the intersection point.
double t;
b01.ClosestPointTo(pinter, &t, true);
b01.SplitAt(t, &b0i, &bi1);
int i, j;
for(i = 0; i < sbl.l.n; i++) {
SBezier *sb = &(sbl.l.elem[i]);
if(sb->deg != 3) oops();
// Add the two cubic segments this one gets split into.
hRequest r0i = AddRequest(Request::CUBIC, false),
ri1 = AddRequest(Request::CUBIC, false);
// Don't get entities till after adding, realloc issues
sb->ClosestPointTo(pinter, &t, false);
if(pinter.Equals(sb->PointAt(t))) {
// Split that segment at the intersection.
SBezier b0i, bi1, b01 = *sb;
b01.SplitAt(t, &b0i, &bi1);
Entity *e0i = SK.GetEntity(r0i.entity(0)),
*ei1 = SK.GetEntity(ri1.entity(0));
// Add the two cubic segments this one gets split into.
hRequest r0i = AddRequest(Request::CUBIC, false),
ri1 = AddRequest(Request::CUBIC, false);
// Don't get entities till after adding, realloc issues
SK.GetEntity(e0i->point[0])->PointForceTo(b0i.ctrl[0]);
SK.GetEntity(e0i->point[1])->PointForceTo(b0i.ctrl[1]);
SK.GetEntity(e0i->point[2])->PointForceTo(b0i.ctrl[2]);
SK.GetEntity(e0i->point[3])->PointForceTo(b0i.ctrl[3]);
Entity *e0i = SK.GetEntity(r0i.entity(0)),
*ei1 = SK.GetEntity(ri1.entity(0));
SK.GetEntity(ei1->point[0])->PointForceTo(bi1.ctrl[0]);
SK.GetEntity(ei1->point[1])->PointForceTo(bi1.ctrl[1]);
SK.GetEntity(ei1->point[2])->PointForceTo(bi1.ctrl[2]);
SK.GetEntity(ei1->point[3])->PointForceTo(bi1.ctrl[3]);
for(j = 0; j <= 3; j++) {
SK.GetEntity(e0i->point[j])->PointForceTo(b0i.ctrl[j]);
}
for(j = 0; j <= 3; j++) {
SK.GetEntity(ei1->point[j])->PointForceTo(bi1.ctrl[j]);
}
ReplacePointInConstraints(hep0, e0i->point[0]);
ReplacePointInConstraints(hep3, ei1->point[3]);
Constraint::ConstrainCoincident(e0i->point[3], ei1->point[0]);
return e0i->point[3];
Constraint::ConstrainCoincident(e0i->point[3], ei1->point[0]);
if(i == 0) hep0n = e0i->point[0];
hep1n = ei1->point[3];
hepin = e0i->point[3];
} else {
hRequest r = AddRequest(Request::CUBIC, false);
Entity *e = SK.GetEntity(r.entity(0));
for(j = 0; j <= 3; j++) {
SK.GetEntity(e->point[j])->PointForceTo(sb->ctrl[j]);
}
if(i == 0) hep0n = e->point[0];
hep1n = e->point[3];
}
}
sbl.Clear();
ReplacePointInConstraints(hep0, hep0n);
ReplacePointInConstraints(hep1, hep1n);
return hepin;
}
hEntity GraphicsWindow::SplitEntity(hEntity he, Vector pinter) {
@ -343,7 +361,7 @@ hEntity GraphicsWindow::SplitEntity(hEntity he, Vector pinter) {
ret = SplitCircle(he, pinter);
} else if(e->type == Entity::LINE_SEGMENT) {
ret = SplitLine(he, pinter);
} else if(e->type == Entity::CUBIC && e->extraPoints == 0) {
} else if(e->type == Entity::CUBIC || e->type == Entity::CUBIC_PERIODIC) {
ret = SplitCubic(he, pinter);
} else {
Error("Couldn't split this entity; lines, circles, or cubics only.");
@ -377,7 +395,11 @@ void GraphicsWindow::SplitLinesOrCurves(void) {
}
GroupSelection();
if(!(gs.n == 2 && (gs.lineSegments + gs.circlesOrArcs + gs.cubics) == 2)) {
if(!(gs.n == 2 &&(gs.lineSegments +
gs.circlesOrArcs +
gs.cubics +
gs.periodicCubics) == 2))
{
Error("Select two entities that intersect each other (e.g. two lines "
"or two circles or a circle and a line).");
return;
@ -402,6 +424,7 @@ void GraphicsWindow::SplitLinesOrCurves(void) {
// If there's multiple points, then just take the first one.
if(inters.l.n > 0) {
Vector pi = inters.l.elem[0].p;
SS.UndoRemember();
hEntity hia = SplitEntity(ha, pi),
hib = SplitEntity(hb, pi);
// SplitEntity adds the coincident constraints to join the split halves

View File

@ -79,6 +79,8 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
if(GraphicsEditControlIsVisible()) return;
if(context.active) return;
pending.drawLine = false;
if(!orig.mouseDown) {
// If someone drags the mouse into our window with the left button
// already depressed, then we don't have our starting point; so
@ -131,6 +133,9 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
} else if(ctrlDown) {
double theta = atan2(orig.mouse.y, orig.mouse.x);
theta -= atan2(y, x);
pending.drawLine = true;
pending.lnA = UnProjectPoint(Point2d::From(0, 0));
pending.lnB = UnProjectPoint(mp);
Vector normal = orig.projRight.Cross(orig.projUp);
projRight = orig.projRight.RotatedAbout(normal, theta);
@ -226,7 +231,14 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
// We're currently dragging something; so do that. But if we haven't
// painted since the last time we solved, do nothing, because there's
// no sense solving a frame and not displaying it.
if(!havePainted) return;
if(!havePainted) {
if(pending.operation == DRAGGING_POINTS && ctrlDown) {
pending.lnA = UnProjectPoint(orig.mouseOnButtonDown);
pending.lnB = UnProjectPoint(mp);
pending.drawLine = true;
}
return;
}
switch(pending.operation) {
case DRAGGING_CONSTRAINT: {
Constraint *c = SK.constraint.FindById(pending.constraint);
@ -267,6 +279,10 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
Vector gn = projRight.Cross(projUp);
qt = Quaternion::From(gn, -theta);
pending.drawLine = true;
pending.lnA = UnProjectPoint(orig.mouseOnButtonDown);
pending.lnB = UnProjectPoint(mp);
} else {
double dx = -(x - orig.mouse.x);
double dy = -(y - orig.mouse.y);
@ -280,7 +296,17 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
List<hEntity> *lhe = &(pending.points);
for(hEntity *he = lhe->First(); he; he = lhe->NextAfter(he)) {
Entity *e = SK.GetEntity(*he);
if(e->type != Entity::POINT_N_ROT_TRANS) continue;
if(e->type != Entity::POINT_N_ROT_TRANS) {
if(ctrlDown) {
Vector p = e->PointGetNum();
p = p.Minus(pending.lnA);
p = qt.Rotate(p);
p = p.Plus(pending.lnA);
e->PointForceTo(p);
SS.MarkGroupDirtyByEntity(e->h);
}
continue;
}
Quaternion q = e->PointGetQuaternion();
Vector p = e->PointGetNum();
@ -439,6 +465,9 @@ void GraphicsWindow::ContextMenuListStyles(void) {
}
void GraphicsWindow::MouseRightUp(double x, double y) {
pending.drawLine = false;
InvalidateGraphics();
// Don't show a context menu if the user is right-clicking the toolbar,
// or if they are finishing a pan.
if(ToolbarMouseMoved((int)x, (int)y)) return;

5
ui.h
View File

@ -242,6 +242,7 @@ public:
MNU_CUT,
MNU_COPY,
MNU_PASTE,
MNU_PASTE_TRANSFORM,
MNU_DELETE,
MNU_SELECT_CHAIN,
MNU_INVERT_SEL,
@ -387,6 +388,9 @@ public:
hEntity circle;
hEntity normal;
hConstraint constraint;
bool drawLine;
Vector lnA, lnB;
char *description;
} pending;
@ -448,6 +452,7 @@ public:
int circlesOrArcs;
int arcs;
int cubics;
int periodicCubics;
int anyNormals;
int vectors;
int constraints;

View File

@ -1,6 +1,6 @@
copy and paste
spline splitting
de-select after left-clicking nothing, keep sel on drag?
-----
associative entities from solid model, as a special group