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;
|
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:
|
default:
|
||||||
oops();
|
oops();
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
|
||||||
{ 1, "&Rectangle\tR", MNU_RECTANGLE, 'R', mReq },
|
{ 1, "&Rectangle\tR", MNU_RECTANGLE, 'R', mReq },
|
||||||
{ 1, "&Circle\tC", 0, 'C', mReq },
|
{ 1, "&Circle\tC", 0, 'C', mReq },
|
||||||
{ 1, "&Arc of a Circle\tA", 0, 'A', 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, NULL, 0, NULL },
|
||||||
{ 1, "Sym&bolic Variable\tB", 0, 'B', mReq },
|
{ 1, "Sym&bolic Variable\tB", 0, 'B', mReq },
|
||||||
{ 1, "&Import From File...\tI", 0, 'I', 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_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_LINE_SEGMENT: s = "click first point of line segment"; goto c;
|
||||||
|
case MNU_CUBIC: s = "click first point of cubic segment"; goto c;
|
||||||
c:
|
c:
|
||||||
SS.GW.pendingOperation = id;
|
SS.GW.pendingOperation = id;
|
||||||
SS.GW.pendingDescription = s;
|
SS.GW.pendingDescription = s;
|
||||||
|
@ -388,54 +389,56 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
||||||
orig.mouse.y = y;
|
orig.mouse.y = y;
|
||||||
|
|
||||||
InvalidateGraphics();
|
InvalidateGraphics();
|
||||||
} else if(leftDown) {
|
return;
|
||||||
// We are left-dragging. This is often used to drag points, or
|
}
|
||||||
// constraint labels.
|
|
||||||
|
// Enforce a bit of static friction before we start dragging.
|
||||||
double dm = orig.mouse.DistanceTo(mp);
|
double dm = orig.mouse.DistanceTo(mp);
|
||||||
// Don't start a drag until we've moved some threshold distance from
|
if(leftDown && dm > 3 && pendingOperation == 0) {
|
||||||
// the mouse-down point, to avoid accidental drags.
|
|
||||||
double dmt = 3;
|
|
||||||
if(pendingOperation == 0) {
|
|
||||||
if(hover.entity.v &&
|
if(hover.entity.v &&
|
||||||
SS.GetEntity(hover.entity)->IsPoint() &&
|
SS.GetEntity(hover.entity)->IsPoint() &&
|
||||||
!SS.GetEntity(hover.entity)->PointIsFromReferences())
|
!SS.GetEntity(hover.entity)->PointIsFromReferences())
|
||||||
{
|
{
|
||||||
if(dm > dmt) {
|
|
||||||
// Start dragging this point.
|
// Start dragging this point.
|
||||||
ClearSelection();
|
ClearSelection();
|
||||||
pendingPoint = hover.entity;
|
pendingPoint = hover.entity;
|
||||||
pendingOperation = DRAGGING_POINT;
|
pendingOperation = DRAGGING_POINT;
|
||||||
}
|
|
||||||
} else if(hover.constraint.v &&
|
} else if(hover.constraint.v &&
|
||||||
SS.GetConstraint(hover.constraint)->HasLabel())
|
SS.GetConstraint(hover.constraint)->HasLabel())
|
||||||
{
|
{
|
||||||
if(dm > dmt) {
|
|
||||||
ClearSelection();
|
ClearSelection();
|
||||||
pendingConstraint = hover.constraint;
|
pendingConstraint = hover.constraint;
|
||||||
pendingOperation = DRAGGING_CONSTRAINT;
|
pendingOperation = DRAGGING_CONSTRAINT;
|
||||||
}
|
}
|
||||||
}
|
} else if(leftDown && pendingOperation == DRAGGING_CONSTRAINT) {
|
||||||
} else if(pendingOperation == DRAGGING_POINT ||
|
|
||||||
pendingOperation == DRAGGING_NEW_POINT ||
|
|
||||||
pendingOperation == DRAGGING_NEW_LINE_POINT)
|
|
||||||
{
|
|
||||||
UpdateDraggedEntity(pendingPoint, x, y);
|
|
||||||
} else if(pendingOperation == DRAGGING_CONSTRAINT) {
|
|
||||||
Constraint *c = SS.constraint.FindById(pendingConstraint);
|
Constraint *c = SS.constraint.FindById(pendingConstraint);
|
||||||
UpdateDraggedPoint(&(c->disp.offset), x, y);
|
UpdateDraggedPoint(&(c->disp.offset), x, y);
|
||||||
|
} else if(leftDown && pendingOperation == DRAGGING_POINT) {
|
||||||
|
UpdateDraggedEntity(pendingPoint, x, y);
|
||||||
|
HitTestMakeSelection(mp);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// No buttons pressed.
|
// No buttons pressed.
|
||||||
if(pendingOperation == DRAGGING_NEW_POINT ||
|
if(pendingOperation == DRAGGING_NEW_POINT ||
|
||||||
pendingOperation == DRAGGING_NEW_LINE_POINT)
|
pendingOperation == DRAGGING_NEW_LINE_POINT)
|
||||||
{
|
{
|
||||||
UpdateDraggedEntity(pendingPoint, x, y);
|
UpdateDraggedEntity(pendingPoint, x, y);
|
||||||
HitTestMakeSelection(mp);
|
HitTestMakeSelection(mp);
|
||||||
} else {
|
} 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.
|
// Do our usual hit testing, for the selection.
|
||||||
HitTestMakeSelection(mp);
|
HitTestMakeSelection(mp);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GraphicsWindow::Selection::Equals(Selection *b) {
|
bool GraphicsWindow::Selection::Equals(Selection *b) {
|
||||||
|
@ -556,6 +559,10 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
||||||
v = v.Plus(projRight.ScaledBy(mx/scale));
|
v = v.Plus(projRight.ScaledBy(mx/scale));
|
||||||
v = v.Plus(projUp.ScaledBy(my/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;
|
hRequest hr;
|
||||||
switch(pendingOperation) {
|
switch(pendingOperation) {
|
||||||
case MNU_DATUM_POINT:
|
case MNU_DATUM_POINT:
|
||||||
|
@ -570,9 +577,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
||||||
case MNU_LINE_SEGMENT:
|
case MNU_LINE_SEGMENT:
|
||||||
hr = AddRequest(Request::LINE_SEGMENT);
|
hr = AddRequest(Request::LINE_SEGMENT);
|
||||||
SS.GetEntity(hr.entity(1))->PointForceTo(v);
|
SS.GetEntity(hr.entity(1))->PointForceTo(v);
|
||||||
if(hover.entity.v && SS.GetEntity(hover.entity)->IsPoint()) {
|
MAYBE_PLACE(hr.entity(1));
|
||||||
Constraint::ConstrainCoincident(hover.entity, hr.entity(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
ClearSelection(); hover.Clear();
|
ClearSelection(); hover.Clear();
|
||||||
|
|
||||||
|
@ -582,12 +587,35 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
||||||
SS.GetEntity(pendingPoint)->PointForceTo(v);
|
SS.GetEntity(pendingPoint)->PointForceTo(v);
|
||||||
break;
|
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:
|
case DRAGGING_NEW_POINT:
|
||||||
// The MouseMoved event has already dragged it under the cursor.
|
// The MouseMoved event has already dragged it under the cursor.
|
||||||
pendingOperation = 0;
|
pendingOperation = 0;
|
||||||
pendingPoint.v = 0;
|
pendingPoint.v = 0;
|
||||||
break;
|
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: {
|
case DRAGGING_NEW_LINE_POINT: {
|
||||||
if(hover.entity.v && SS.GetEntity(hover.entity)->IsPoint()) {
|
if(hover.entity.v && SS.GetEntity(hover.entity)->IsPoint()) {
|
||||||
Constraint::ConstrainCoincident(pendingPoint, hover.entity);
|
Constraint::ConstrainCoincident(pendingPoint, hover.entity);
|
||||||
|
@ -614,6 +642,9 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
||||||
case 0:
|
case 0:
|
||||||
default: {
|
default: {
|
||||||
pendingOperation = 0;
|
pendingOperation = 0;
|
||||||
|
pendingPoint.v = 0;
|
||||||
|
pendingConstraint.v = 0;
|
||||||
|
pendingDescription = NULL;
|
||||||
|
|
||||||
if(hover.IsEmpty()) break;
|
if(hover.IsEmpty()) break;
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,9 @@ void Request::Generate(IdList<Entity,hEntity> *entity,
|
||||||
|
|
||||||
case Request::LINE_SEGMENT:
|
case Request::LINE_SEGMENT:
|
||||||
et = Entity::LINE_SEGMENT; points = 2; params = 0; goto c;
|
et = Entity::LINE_SEGMENT; points = 2; params = 0; goto c;
|
||||||
|
|
||||||
|
case Request::CUBIC:
|
||||||
|
et = Entity::CUBIC; points = 4; params = 0; goto c;
|
||||||
c: {
|
c: {
|
||||||
// Generate the entity that's specific to this request.
|
// Generate the entity that's specific to this request.
|
||||||
e.type = et;
|
e.type = et;
|
||||||
|
|
2
sketch.h
2
sketch.h
|
@ -106,6 +106,7 @@ public:
|
||||||
static const int CSYS_2D = 100;
|
static const int CSYS_2D = 100;
|
||||||
static const int DATUM_POINT = 101;
|
static const int DATUM_POINT = 101;
|
||||||
static const int LINE_SEGMENT = 200;
|
static const int LINE_SEGMENT = 200;
|
||||||
|
static const int CUBIC = 300;
|
||||||
|
|
||||||
int type;
|
int type;
|
||||||
|
|
||||||
|
@ -138,6 +139,7 @@ public:
|
||||||
static const int POINT_IN_3D = 2000;
|
static const int POINT_IN_3D = 2000;
|
||||||
static const int POINT_IN_2D = 2001;
|
static const int POINT_IN_2D = 2001;
|
||||||
static const int LINE_SEGMENT = 3000;
|
static const int LINE_SEGMENT = 3000;
|
||||||
|
static const int CUBIC = 4000;
|
||||||
int type;
|
int type;
|
||||||
|
|
||||||
bool symbolic;
|
bool symbolic;
|
||||||
|
|
4
ui.h
4
ui.h
|
@ -98,6 +98,7 @@ public:
|
||||||
MNU_DATUM_POINT,
|
MNU_DATUM_POINT,
|
||||||
MNU_LINE_SEGMENT,
|
MNU_LINE_SEGMENT,
|
||||||
MNU_RECTANGLE,
|
MNU_RECTANGLE,
|
||||||
|
MNU_CUBIC,
|
||||||
// Constrain
|
// Constrain
|
||||||
MNU_DISTANCE_DIA,
|
MNU_DISTANCE_DIA,
|
||||||
MNU_EQUAL,
|
MNU_EQUAL,
|
||||||
|
@ -154,7 +155,8 @@ public:
|
||||||
static const int DRAGGING_POINT = 0x0f000000;
|
static const int DRAGGING_POINT = 0x0f000000;
|
||||||
static const int DRAGGING_NEW_POINT = 0x0f000001;
|
static const int DRAGGING_NEW_POINT = 0x0f000001;
|
||||||
static const int DRAGGING_NEW_LINE_POINT = 0x0f000002;
|
static const int DRAGGING_NEW_LINE_POINT = 0x0f000002;
|
||||||
static const int DRAGGING_CONSTRAINT = 0x0f000003;
|
static const int DRAGGING_NEW_CUBIC_POINT = 0x0f000003;
|
||||||
|
static const int DRAGGING_CONSTRAINT = 0x0f000004;
|
||||||
hEntity pendingPoint;
|
hEntity pendingPoint;
|
||||||
hConstraint pendingConstraint;
|
hConstraint pendingConstraint;
|
||||||
int pendingOperation;
|
int pendingOperation;
|
||||||
|
|
Loading…
Reference in New Issue