Add cubics, and tweak mouse handling code.
[git-p4: depot-paths = "//depot/solvespace/": change = 1689]solver
parent
c934737d9e
commit
5bc3738ec4
20
entity.cpp
20
entity.cpp
|
@ -321,6 +321,26 @@ void Entity::DrawOrGetDistance(int order) {
|
|||
break;
|
||||
}
|
||||
|
||||
case CUBIC: {
|
||||
Vector p0 = SS.GetEntity(assoc[0])->PointGetCoords();
|
||||
Vector p1 = SS.GetEntity(assoc[1])->PointGetCoords();
|
||||
Vector p2 = SS.GetEntity(assoc[2])->PointGetCoords();
|
||||
Vector p3 = SS.GetEntity(assoc[3])->PointGetCoords();
|
||||
int i, n = 20;
|
||||
Vector prev = p0;
|
||||
for(i = 1; i <= n; i++) {
|
||||
double t = ((double)i)/n;
|
||||
Vector p =
|
||||
(p0.ScaledBy((1 - t)*(1 - t)*(1 - t))).Plus(
|
||||
(p1.ScaledBy(3*t*(1 - t)*(1 - t))).Plus(
|
||||
(p2.ScaledBy(3*t*t*(1 - t))).Plus(
|
||||
(p3.ScaledBy(t*t*t)))));
|
||||
LineDrawOrGetDistanceOrEdge(prev, p);
|
||||
prev = p;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
oops();
|
||||
}
|
||||
|
|
127
graphicswin.cpp
127
graphicswin.cpp
|
@ -58,7 +58,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
|
|||
{ 1, "&Rectangle\tR", MNU_RECTANGLE, 'R', mReq },
|
||||
{ 1, "&Circle\tC", 0, 'C', mReq },
|
||||
{ 1, "&Arc of a Circle\tA", 0, 'A', mReq },
|
||||
{ 1, "&Cubic Segment\t3", 0, '3', mReq },
|
||||
{ 1, "&Cubic Segment\t3", MNU_CUBIC, '3', mReq },
|
||||
{ 1, NULL, 0, NULL },
|
||||
{ 1, "Sym&bolic Variable\tB", 0, 'B', mReq },
|
||||
{ 1, "&Import From File...\tI", 0, 'I', mReq },
|
||||
|
@ -320,6 +320,7 @@ void GraphicsWindow::MenuRequest(int id) {
|
|||
|
||||
case MNU_DATUM_POINT: s = "click to place datum point"; goto c;
|
||||
case MNU_LINE_SEGMENT: s = "click first point of line segment"; goto c;
|
||||
case MNU_CUBIC: s = "click first point of cubic segment"; goto c;
|
||||
c:
|
||||
SS.GW.pendingOperation = id;
|
||||
SS.GW.pendingDescription = s;
|
||||
|
@ -388,53 +389,55 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
|||
orig.mouse.y = y;
|
||||
|
||||
InvalidateGraphics();
|
||||
} else if(leftDown) {
|
||||
// We are left-dragging. This is often used to drag points, or
|
||||
// constraint labels.
|
||||
double dm = orig.mouse.DistanceTo(mp);
|
||||
// Don't start a drag until we've moved some threshold distance from
|
||||
// the mouse-down point, to avoid accidental drags.
|
||||
double dmt = 3;
|
||||
if(pendingOperation == 0) {
|
||||
if(hover.entity.v &&
|
||||
SS.GetEntity(hover.entity)->IsPoint() &&
|
||||
!SS.GetEntity(hover.entity)->PointIsFromReferences())
|
||||
{
|
||||
if(dm > dmt) {
|
||||
// Start dragging this point.
|
||||
ClearSelection();
|
||||
pendingPoint = hover.entity;
|
||||
pendingOperation = DRAGGING_POINT;
|
||||
}
|
||||
} else if(hover.constraint.v &&
|
||||
SS.GetConstraint(hover.constraint)->HasLabel())
|
||||
{
|
||||
if(dm > dmt) {
|
||||
ClearSelection();
|
||||
pendingConstraint = hover.constraint;
|
||||
pendingOperation = DRAGGING_CONSTRAINT;
|
||||
}
|
||||
}
|
||||
} else if(pendingOperation == DRAGGING_POINT ||
|
||||
pendingOperation == DRAGGING_NEW_POINT ||
|
||||
pendingOperation == DRAGGING_NEW_LINE_POINT)
|
||||
return;
|
||||
}
|
||||
|
||||
// Enforce a bit of static friction before we start dragging.
|
||||
double dm = orig.mouse.DistanceTo(mp);
|
||||
if(leftDown && dm > 3 && pendingOperation == 0) {
|
||||
if(hover.entity.v &&
|
||||
SS.GetEntity(hover.entity)->IsPoint() &&
|
||||
!SS.GetEntity(hover.entity)->PointIsFromReferences())
|
||||
{
|
||||
UpdateDraggedEntity(pendingPoint, x, y);
|
||||
} else if(pendingOperation == DRAGGING_CONSTRAINT) {
|
||||
Constraint *c = SS.constraint.FindById(pendingConstraint);
|
||||
UpdateDraggedPoint(&(c->disp.offset), x, y);
|
||||
}
|
||||
} else {
|
||||
// No buttons pressed.
|
||||
if(pendingOperation == DRAGGING_NEW_POINT ||
|
||||
pendingOperation == DRAGGING_NEW_LINE_POINT)
|
||||
// Start dragging this point.
|
||||
ClearSelection();
|
||||
pendingPoint = hover.entity;
|
||||
pendingOperation = DRAGGING_POINT;
|
||||
} else if(hover.constraint.v &&
|
||||
SS.GetConstraint(hover.constraint)->HasLabel())
|
||||
{
|
||||
UpdateDraggedEntity(pendingPoint, x, y);
|
||||
HitTestMakeSelection(mp);
|
||||
} else {
|
||||
// Do our usual hit testing, for the selection.
|
||||
HitTestMakeSelection(mp);
|
||||
ClearSelection();
|
||||
pendingConstraint = hover.constraint;
|
||||
pendingOperation = DRAGGING_CONSTRAINT;
|
||||
}
|
||||
} else if(leftDown && pendingOperation == DRAGGING_CONSTRAINT) {
|
||||
Constraint *c = SS.constraint.FindById(pendingConstraint);
|
||||
UpdateDraggedPoint(&(c->disp.offset), x, y);
|
||||
} else if(leftDown && pendingOperation == DRAGGING_POINT) {
|
||||
UpdateDraggedEntity(pendingPoint, x, y);
|
||||
HitTestMakeSelection(mp);
|
||||
}
|
||||
|
||||
// No buttons pressed.
|
||||
if(pendingOperation == DRAGGING_NEW_POINT ||
|
||||
pendingOperation == DRAGGING_NEW_LINE_POINT)
|
||||
{
|
||||
UpdateDraggedEntity(pendingPoint, x, y);
|
||||
HitTestMakeSelection(mp);
|
||||
} else if(pendingOperation == DRAGGING_NEW_CUBIC_POINT) {
|
||||
UpdateDraggedEntity(pendingPoint, x, y);
|
||||
HitTestMakeSelection(mp);
|
||||
|
||||
hRequest hr = pendingPoint.request();
|
||||
Vector p0 = SS.GetEntity(hr.entity(1))->PointGetCoords();
|
||||
Vector p3 = SS.GetEntity(hr.entity(4))->PointGetCoords();
|
||||
Vector p1 = p0.ScaledBy(2.0/3).Plus(p3.ScaledBy(1.0/3));
|
||||
SS.GetEntity(hr.entity(2))->PointForceTo(p1);
|
||||
Vector p2 = p0.ScaledBy(1.0/3).Plus(p3.ScaledBy(2.0/3));
|
||||
SS.GetEntity(hr.entity(3))->PointForceTo(p2);
|
||||
} else if(!leftDown) {
|
||||
// Do our usual hit testing, for the selection.
|
||||
HitTestMakeSelection(mp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -556,6 +559,10 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
|||
v = v.Plus(projRight.ScaledBy(mx/scale));
|
||||
v = v.Plus(projUp.ScaledBy(my/scale));
|
||||
|
||||
#define MAYBE_PLACE(p) \
|
||||
if(hover.entity.v && SS.GetEntity((p))->IsPoint()) { \
|
||||
Constraint::ConstrainCoincident(hover.entity, (p)); \
|
||||
}
|
||||
hRequest hr;
|
||||
switch(pendingOperation) {
|
||||
case MNU_DATUM_POINT:
|
||||
|
@ -570,9 +577,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
|||
case MNU_LINE_SEGMENT:
|
||||
hr = AddRequest(Request::LINE_SEGMENT);
|
||||
SS.GetEntity(hr.entity(1))->PointForceTo(v);
|
||||
if(hover.entity.v && SS.GetEntity(hover.entity)->IsPoint()) {
|
||||
Constraint::ConstrainCoincident(hover.entity, hr.entity(1));
|
||||
}
|
||||
MAYBE_PLACE(hr.entity(1));
|
||||
|
||||
ClearSelection(); hover.Clear();
|
||||
|
||||
|
@ -582,12 +587,35 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
|||
SS.GetEntity(pendingPoint)->PointForceTo(v);
|
||||
break;
|
||||
|
||||
case MNU_CUBIC:
|
||||
hr = AddRequest(Request::CUBIC);
|
||||
SS.GetEntity(hr.entity(1))->PointForceTo(v);
|
||||
SS.GetEntity(hr.entity(2))->PointForceTo(v);
|
||||
SS.GetEntity(hr.entity(3))->PointForceTo(v);
|
||||
SS.GetEntity(hr.entity(4))->PointForceTo(v);
|
||||
MAYBE_PLACE(hr.entity(1));
|
||||
|
||||
ClearSelection(); hover.Clear();
|
||||
|
||||
pendingOperation = DRAGGING_NEW_CUBIC_POINT;
|
||||
pendingPoint = hr.entity(4);
|
||||
pendingDescription = "click to place next point of cubic";
|
||||
break;
|
||||
|
||||
case DRAGGING_NEW_POINT:
|
||||
// The MouseMoved event has already dragged it under the cursor.
|
||||
pendingOperation = 0;
|
||||
pendingPoint.v = 0;
|
||||
break;
|
||||
|
||||
case DRAGGING_NEW_CUBIC_POINT:
|
||||
if(hover.entity.v && SS.GetEntity(hover.entity)->IsPoint()) {
|
||||
Constraint::ConstrainCoincident(pendingPoint, hover.entity);
|
||||
}
|
||||
pendingOperation = 0;
|
||||
pendingPoint.v = 0;
|
||||
break;
|
||||
|
||||
case DRAGGING_NEW_LINE_POINT: {
|
||||
if(hover.entity.v && SS.GetEntity(hover.entity)->IsPoint()) {
|
||||
Constraint::ConstrainCoincident(pendingPoint, hover.entity);
|
||||
|
@ -614,6 +642,9 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
|||
case 0:
|
||||
default: {
|
||||
pendingOperation = 0;
|
||||
pendingPoint.v = 0;
|
||||
pendingConstraint.v = 0;
|
||||
pendingDescription = NULL;
|
||||
|
||||
if(hover.IsEmpty()) break;
|
||||
|
||||
|
|
|
@ -80,6 +80,9 @@ void Request::Generate(IdList<Entity,hEntity> *entity,
|
|||
|
||||
case Request::LINE_SEGMENT:
|
||||
et = Entity::LINE_SEGMENT; points = 2; params = 0; goto c;
|
||||
|
||||
case Request::CUBIC:
|
||||
et = Entity::CUBIC; points = 4; params = 0; goto c;
|
||||
c: {
|
||||
// Generate the entity that's specific to this request.
|
||||
e.type = et;
|
||||
|
|
2
sketch.h
2
sketch.h
|
@ -106,6 +106,7 @@ public:
|
|||
static const int CSYS_2D = 100;
|
||||
static const int DATUM_POINT = 101;
|
||||
static const int LINE_SEGMENT = 200;
|
||||
static const int CUBIC = 300;
|
||||
|
||||
int type;
|
||||
|
||||
|
@ -138,6 +139,7 @@ public:
|
|||
static const int POINT_IN_3D = 2000;
|
||||
static const int POINT_IN_2D = 2001;
|
||||
static const int LINE_SEGMENT = 3000;
|
||||
static const int CUBIC = 4000;
|
||||
int type;
|
||||
|
||||
bool symbolic;
|
||||
|
|
10
ui.h
10
ui.h
|
@ -98,6 +98,7 @@ public:
|
|||
MNU_DATUM_POINT,
|
||||
MNU_LINE_SEGMENT,
|
||||
MNU_RECTANGLE,
|
||||
MNU_CUBIC,
|
||||
// Constrain
|
||||
MNU_DISTANCE_DIA,
|
||||
MNU_EQUAL,
|
||||
|
@ -151,10 +152,11 @@ public:
|
|||
|
||||
// Operations that must be completed by doing something with the mouse
|
||||
// are noted here.
|
||||
static const int DRAGGING_POINT = 0x0f000000;
|
||||
static const int DRAGGING_NEW_POINT = 0x0f000001;
|
||||
static const int DRAGGING_NEW_LINE_POINT = 0x0f000002;
|
||||
static const int DRAGGING_CONSTRAINT = 0x0f000003;
|
||||
static const int DRAGGING_POINT = 0x0f000000;
|
||||
static const int DRAGGING_NEW_POINT = 0x0f000001;
|
||||
static const int DRAGGING_NEW_LINE_POINT = 0x0f000002;
|
||||
static const int DRAGGING_NEW_CUBIC_POINT = 0x0f000003;
|
||||
static const int DRAGGING_CONSTRAINT = 0x0f000004;
|
||||
hEntity pendingPoint;
|
||||
hConstraint pendingConstraint;
|
||||
int pendingOperation;
|
||||
|
|
Loading…
Reference in New Issue