Some graphics tweaks, to the order in which stuff gets drawn, to
determine what goes in front (e.g. put a drawn line in front of the reference plane, even if the z order would want the opposite), and some tweaks to the mouse behaviour, and a function to modify constraints like dimensions so that the are initially satisfied. [git-p4: depot-paths = "//depot/solvespace/": change = 1681]solver
parent
1f77024771
commit
fa71238def
|
@ -29,7 +29,8 @@ void Constraint::MenuConstrain(int id) {
|
|||
return;
|
||||
}
|
||||
c.disp.offset = Vector::MakeFrom(50, 50, 50);
|
||||
c.exprA = Expr::FromString("300")->DeepCopyKeep();
|
||||
c.exprA = Expr::FromString("0")->DeepCopyKeep();
|
||||
c.ModifyToSatisfy();
|
||||
AddConstraint(&c);
|
||||
break;
|
||||
|
||||
|
@ -103,6 +104,24 @@ Expr *Constraint::Distance(hEntity hpa, hEntity hpb) {
|
|||
return (dx2->Plus(dy2->Plus(dz2)))->Sqrt();
|
||||
}
|
||||
|
||||
void Constraint::ModifyToSatisfy(void) {
|
||||
IdList<Equation,hEquation> l;
|
||||
// An uninit IdList could lead us to free some random address, bad.
|
||||
memset(&l, 0, sizeof(l));
|
||||
|
||||
Generate(&l);
|
||||
if(l.n != 1) oops();
|
||||
|
||||
// These equations are written in the form f(...) - d = 0, where
|
||||
// d is the value of the exprA.
|
||||
double v = (l.elem[0].e)->Eval();
|
||||
double nd = exprA->Eval() + v;
|
||||
Expr::FreeKeep(&exprA);
|
||||
exprA = Expr::FromConstant(nd)->DeepCopyKeep();
|
||||
|
||||
l.Clear();
|
||||
}
|
||||
|
||||
void Constraint::AddEq(IdList<Equation,hEquation> *l, Expr *expr, int index) {
|
||||
Equation eq;
|
||||
eq.e = expr;
|
||||
|
|
|
@ -67,14 +67,25 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||
}
|
||||
|
||||
case POINTS_COINCIDENT: {
|
||||
// It's impossible to select this constraint on the drawing;
|
||||
// have to do it from the text window.
|
||||
if(!dogd.drawing) break;
|
||||
double s = 2;
|
||||
Vector r = SS.GW.projRight.ScaledBy(s/SS.GW.scale);
|
||||
Vector d = SS.GW.projUp.ScaledBy(s/SS.GW.scale);
|
||||
if(!dogd.drawing) {
|
||||
for(int i = 0; i < 2; i++) {
|
||||
Vector p = SS.GetEntity(i == 0 ? ptA : ptB)->PointGetCoords();
|
||||
Vector p = SS.GetEntity(i == 0 ? ptA : ptB)->
|
||||
PointGetCoords();
|
||||
Point2d pp = SS.GW.ProjectPoint(p);
|
||||
// The point is selected within a radius of 7, from the
|
||||
// same center; so if the point is visible, then this
|
||||
// constraint cannot be selected. But that's okay.
|
||||
dogd.dmin = min(dogd.dmin, pp.DistanceTo(dogd.mp) - 3);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
for(int a = 0; a < 2; a++) {
|
||||
Vector r = SS.GW.projRight.ScaledBy((a+1)/SS.GW.scale);
|
||||
Vector d = SS.GW.projUp.ScaledBy((2-a)/SS.GW.scale);
|
||||
for(int i = 0; i < 2; i++) {
|
||||
Vector p = SS.GetEntity(i == 0 ? ptA : ptB)->
|
||||
PointGetCoords();
|
||||
glxColor(0.4, 0, 0.4);
|
||||
glBegin(GL_QUADS);
|
||||
glxVertex3v(p.Plus (r).Plus (d));
|
||||
|
@ -83,11 +94,13 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||
glxVertex3v(p.Minus(r).Plus (d));
|
||||
glEnd();
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PT_IN_PLANE: {
|
||||
double s = 6;
|
||||
double s = 5;
|
||||
Vector r = SS.GW.projRight.ScaledBy(s/SS.GW.scale);
|
||||
Vector d = SS.GW.projUp.ScaledBy(s/SS.GW.scale);
|
||||
Vector p = SS.GetEntity(ptA)->PointGetCoords();
|
||||
|
|
17
entity.cpp
17
entity.cpp
|
@ -191,9 +191,9 @@ void Entity::LineDrawOrGetDistance(Vector a, Vector b) {
|
|||
}
|
||||
}
|
||||
|
||||
void Entity::Draw(void) {
|
||||
void Entity::Draw(int order) {
|
||||
dogd.drawing = true;
|
||||
DrawOrGetDistance();
|
||||
DrawOrGetDistance(order);
|
||||
}
|
||||
|
||||
double Entity::GetDistance(Point2d mp) {
|
||||
|
@ -201,17 +201,18 @@ double Entity::GetDistance(Point2d mp) {
|
|||
dogd.mp = mp;
|
||||
dogd.dmin = 1e12;
|
||||
|
||||
DrawOrGetDistance();
|
||||
DrawOrGetDistance(-1);
|
||||
|
||||
return dogd.dmin;
|
||||
}
|
||||
|
||||
void Entity::DrawOrGetDistance(void) {
|
||||
void Entity::DrawOrGetDistance(int order) {
|
||||
glxColor(1, 1, 1);
|
||||
|
||||
switch(type) {
|
||||
case POINT_IN_3D:
|
||||
case POINT_IN_2D: {
|
||||
if(order >= 0 && order != 2) break;
|
||||
if(!SS.GW.showPoints) break;
|
||||
|
||||
Entity *isfor = SS.GetEntity(h.request().entity(0));
|
||||
|
@ -220,25 +221,28 @@ void Entity::DrawOrGetDistance(void) {
|
|||
Vector v = PointGetCoords();
|
||||
|
||||
if(dogd.drawing) {
|
||||
double s = 4;
|
||||
double s = 3;
|
||||
Vector r = SS.GW.projRight.ScaledBy(s/SS.GW.scale);
|
||||
Vector d = SS.GW.projUp.ScaledBy(s/SS.GW.scale);
|
||||
|
||||
glxColor(0, 0.8, 0);
|
||||
glDisable(GL_LINE_SMOOTH);
|
||||
glBegin(GL_QUADS);
|
||||
glxVertex3v(v.Plus (r).Plus (d));
|
||||
glxVertex3v(v.Plus (r).Minus(d));
|
||||
glxVertex3v(v.Minus(r).Minus(d));
|
||||
glxVertex3v(v.Minus(r).Plus (d));
|
||||
glEnd();
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
} else {
|
||||
Point2d pp = SS.GW.ProjectPoint(v);
|
||||
dogd.dmin = pp.DistanceTo(dogd.mp) - 8;
|
||||
dogd.dmin = pp.DistanceTo(dogd.mp) - 7;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CSYS_2D: {
|
||||
if(order >= 0 && order != 0) break;
|
||||
if(!SS.GW.show2dCsyss) break;
|
||||
|
||||
Vector p;
|
||||
|
@ -274,6 +278,7 @@ void Entity::DrawOrGetDistance(void) {
|
|||
}
|
||||
|
||||
case LINE_SEGMENT: {
|
||||
if(order >= 0 && order != 1) break;
|
||||
Vector a = SS.GetEntity(assoc[0])->PointGetCoords();
|
||||
Vector b = SS.GetEntity(assoc[1])->PointGetCoords();
|
||||
LineDrawOrGetDistance(a, b);
|
||||
|
|
|
@ -37,6 +37,17 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
|
|||
{ 1, "Dimensions in &Inches", 0, NULL },
|
||||
{ 1, "Dimensions in &Millimeters", 0, NULL },
|
||||
|
||||
{ 0, "&Group", 0, 0, NULL },
|
||||
{ 1, "New &Drawing Group", 0, 0, NULL },
|
||||
{ 1, NULL, 0, NULL },
|
||||
{ 1, "New Step and Repeat &Translating", 0, 0, NULL },
|
||||
{ 1, "New Step and Repeat &Rotating", 0, 0, NULL },
|
||||
{ 1, NULL, 0, 0, NULL },
|
||||
{ 1, "New Extrusion", 0, 0, NULL },
|
||||
{ 1, NULL, 0, 0, NULL },
|
||||
{ 1, "New Boolean Difference", 0, 0, NULL },
|
||||
{ 1, "New Boolean Union", 0, 0, NULL },
|
||||
|
||||
{ 0, "&Request", 0, NULL },
|
||||
{ 1, "Dra&w in 2d Coordinate System\tW", MNU_SEL_CSYS, 'W', mReq },
|
||||
{ 1, "Draw Anywhere in 3d\tQ", MNU_NO_CSYS, 'Q', mReq },
|
||||
|
@ -47,15 +58,11 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
|
|||
{ 1, "2d Coordinate S&ystem\tY", 0, 'Y', mReq },
|
||||
{ 1, NULL, 0, NULL },
|
||||
{ 1, "Line &Segment\tS", MNU_LINE_SEGMENT, 'S', mReq },
|
||||
{ 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, NULL, 0, NULL },
|
||||
{ 1, "Boolean &Union\tU", 0, 'U', mReq },
|
||||
{ 1, "Boolean &Difference\tD", 0, 'D', mReq },
|
||||
{ 1, "Step and Repeat &Translate\tT", 0, 'T', mReq },
|
||||
{ 1, "Step and Repeat &Rotate\tR", 0, 'R', mReq },
|
||||
{ 1, NULL, 0, NULL },
|
||||
{ 1, "Sym&bolic Variable\tB", 0, 'B', mReq },
|
||||
{ 1, "&Import From File...\tI", 0, 'I', mReq },
|
||||
{ 1, NULL, 0, NULL },
|
||||
|
@ -223,7 +230,9 @@ void GraphicsWindow::EnsureValidActives(void) {
|
|||
}
|
||||
if(change) SS.TW.Show();
|
||||
|
||||
EnableMenuById(MNU_NO_CSYS, (activeCsys.v != Entity::NO_CSYS.v));
|
||||
bool in3d = (activeCsys.v == Entity::NO_CSYS.v);
|
||||
CheckMenuById(MNU_NO_CSYS, in3d);
|
||||
CheckMenuById(MNU_SEL_CSYS, !in3d);
|
||||
}
|
||||
|
||||
void GraphicsWindow::MenuEdit(int id) {
|
||||
|
@ -359,21 +368,41 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
|||
} 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();
|
||||
UpdateDraggedEntity(hover.entity, x, y);
|
||||
pendingPoint = hover.entity;
|
||||
pendingOperation = PENDING_OPERATION_DRAGGING_POINT;
|
||||
}
|
||||
} else if(hover.constraint.v &&
|
||||
SS.GetConstraint(hover.constraint)->HasLabel())
|
||||
{
|
||||
if(dm > dmt) {
|
||||
ClearSelection();
|
||||
Constraint *c = SS.constraint.FindById(hover.constraint);
|
||||
pendingConstraint = hover.constraint;
|
||||
pendingOperation = PENDING_OPERATION_DRAGGING_CONSTRAINT;
|
||||
}
|
||||
}
|
||||
} else if(pendingOperation == PENDING_OPERATION_DRAGGING_POINT ||
|
||||
pendingOperation == PENDING_OPERATION_DRAGGING_NEW_POINT)
|
||||
{
|
||||
UpdateDraggedEntity(pendingPoint, x, y);
|
||||
} else if(pendingOperation == PENDING_OPERATION_DRAGGING_CONSTRAINT) {
|
||||
Constraint *c = SS.constraint.FindById(pendingConstraint);
|
||||
UpdateDraggedPoint(&(c->disp.offset), x, y);
|
||||
}
|
||||
} else {
|
||||
if(pendingOperation == PENDING_OPERATION_DRAGGING_POINT) {
|
||||
// No buttons pressed.
|
||||
if(pendingOperation == PENDING_OPERATION_DRAGGING_NEW_POINT) {
|
||||
UpdateDraggedEntity(pendingPoint, x, y);
|
||||
} else {
|
||||
// Do our usual hit testing, for the selection.
|
||||
|
@ -401,7 +430,7 @@ void GraphicsWindow::Selection::Clear(void) {
|
|||
entity.v = constraint.v = 0;
|
||||
}
|
||||
void GraphicsWindow::Selection::Draw(void) {
|
||||
if(entity.v) SS.GetEntity (entity )->Draw();
|
||||
if(entity.v) SS.GetEntity (entity )->Draw(-1);
|
||||
if(constraint.v) SS.GetConstraint(constraint)->Draw();
|
||||
}
|
||||
|
||||
|
@ -499,21 +528,27 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
|||
hRequest hr;
|
||||
switch(pendingOperation) {
|
||||
case MNU_DATUM_POINT:
|
||||
ClearSelection(); hover.Clear();
|
||||
|
||||
hr = AddRequest(Request::DATUM_POINT);
|
||||
SS.GetEntity(hr.entity(0))->PointForceTo(v);
|
||||
|
||||
pendingOperation = 0;
|
||||
break;
|
||||
|
||||
case MNU_LINE_SEGMENT:
|
||||
ClearSelection(); hover.Clear();
|
||||
|
||||
hr = AddRequest(Request::LINE_SEGMENT);
|
||||
SS.GetEntity(hr.entity(1))->PointForceTo(v);
|
||||
pendingOperation = PENDING_OPERATION_DRAGGING_POINT;
|
||||
|
||||
pendingOperation = PENDING_OPERATION_DRAGGING_NEW_POINT;
|
||||
pendingPoint = hr.entity(2);
|
||||
pendingDescription = "click to place next point of line";
|
||||
SS.GetEntity(pendingPoint)->PointForceTo(v);
|
||||
break;
|
||||
|
||||
case PENDING_OPERATION_DRAGGING_POINT:
|
||||
case PENDING_OPERATION_DRAGGING_NEW_POINT:
|
||||
// The MouseMoved event has already dragged it under the cursor.
|
||||
pendingOperation = 0;
|
||||
break;
|
||||
|
@ -549,6 +584,20 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
|||
InvalidateGraphics();
|
||||
}
|
||||
|
||||
void GraphicsWindow::MouseLeftUp(double mx, double my) {
|
||||
switch(pendingOperation) {
|
||||
case PENDING_OPERATION_DRAGGING_POINT:
|
||||
case PENDING_OPERATION_DRAGGING_CONSTRAINT:
|
||||
pendingOperation = 0;
|
||||
pendingPoint.v = 0;
|
||||
pendingConstraint.v = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
break; // do nothing
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsWindow::MouseLeftDoubleClick(double mx, double my) {
|
||||
if(GraphicsEditControlIsVisible()) return;
|
||||
|
||||
|
@ -649,16 +698,22 @@ void GraphicsWindow::Paint(int w, int h) {
|
|||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
|
||||
int i;
|
||||
int i, a;
|
||||
|
||||
// First, draw the entire scene.
|
||||
// First, draw the entire scene. We don't necessarily want to draw
|
||||
// things with normal z-buffering behaviour; e.g. we always want to
|
||||
// draw a line segment in front of a reference. So we have three draw
|
||||
// levels, and only the first gets normal depth testing.
|
||||
glxUnlockColor();
|
||||
for(a = 0; a <= 2; a++) {
|
||||
// Three levels: 0 least prominent (e.g. a reference csys), 1 is
|
||||
// middle (e.g. line segment), 2 is always in front (e.g. point).
|
||||
if(a == 1) glDisable(GL_DEPTH_TEST);
|
||||
for(i = 0; i < SS.entity.n; i++) {
|
||||
SS.entity.elem[i].Draw();
|
||||
SS.entity.elem[i].Draw(a);
|
||||
}
|
||||
}
|
||||
|
||||
// Want the constraints to get drawn in front, so disable depth test.
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
// Draw the constraints
|
||||
for(i = 0; i < SS.constraint.n; i++) {
|
||||
SS.constraint.elem[i].Draw();
|
||||
|
|
5
sketch.h
5
sketch.h
|
@ -164,8 +164,8 @@ public:
|
|||
double dmin;
|
||||
} dogd;
|
||||
void LineDrawOrGetDistance(Vector a, Vector b);
|
||||
void DrawOrGetDistance(void);
|
||||
void Draw(void);
|
||||
void DrawOrGetDistance(int order);
|
||||
void Draw(int order);
|
||||
double GetDistance(Point2d mp);
|
||||
|
||||
char *DescriptionString(void);
|
||||
|
@ -257,6 +257,7 @@ public:
|
|||
|
||||
void Generate(IdList<Equation,hEquation> *l);
|
||||
// Some helpers when generating symbolic constraint equations
|
||||
void ModifyToSatisfy(void);
|
||||
void AddEq(IdList<Equation,hEquation> *l, Expr *expr, int index);
|
||||
static Expr *Distance(hEntity pa, hEntity pb);
|
||||
};
|
||||
|
|
5
ui.h
5
ui.h
|
@ -94,6 +94,7 @@ public:
|
|||
MNU_NO_CSYS,
|
||||
MNU_DATUM_POINT,
|
||||
MNU_LINE_SEGMENT,
|
||||
MNU_RECTANGLE,
|
||||
// Constrain
|
||||
MNU_DISTANCE_DIA,
|
||||
MNU_EQUAL,
|
||||
|
@ -140,7 +141,10 @@ public:
|
|||
// Operations that must be completed by doing something with the mouse
|
||||
// are noted here.
|
||||
static const int PENDING_OPERATION_DRAGGING_POINT = 0x0f000000;
|
||||
static const int PENDING_OPERATION_DRAGGING_NEW_POINT = 0x0f000001;
|
||||
static const int PENDING_OPERATION_DRAGGING_CONSTRAINT = 0x0f000002;
|
||||
hEntity pendingPoint;
|
||||
hConstraint pendingConstraint;
|
||||
int pendingOperation;
|
||||
char *pendingDescription;
|
||||
hRequest AddRequest(int type);
|
||||
|
@ -194,6 +198,7 @@ public:
|
|||
void MouseMoved(double x, double y, bool leftDown, bool middleDown,
|
||||
bool rightDown, bool shiftDown, bool ctrlDown);
|
||||
void MouseLeftDown(double x, double y);
|
||||
void MouseLeftUp(double x, double y);
|
||||
void MouseLeftDoubleClick(double x, double y);
|
||||
void MouseMiddleDown(double x, double y);
|
||||
void MouseScroll(double x, double y, int delta);
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
#include "freeze.h"
|
||||
|
||||
#define MIN_COLS 42
|
||||
#define TEXT_HEIGHT 19
|
||||
#define TEXT_WIDTH 10
|
||||
#define TEXT_HEIGHT 18
|
||||
#define TEXT_WIDTH 9
|
||||
|
||||
HINSTANCE Instance;
|
||||
|
||||
|
@ -446,6 +446,7 @@ LRESULT CALLBACK GraphicsWndProc(HWND hwnd, UINT msg, WPARAM wParam,
|
|||
|
||||
case WM_MOUSEMOVE:
|
||||
case WM_LBUTTONDOWN:
|
||||
case WM_LBUTTONUP:
|
||||
case WM_LBUTTONDBLCLK:
|
||||
case WM_MBUTTONDOWN: {
|
||||
int x = LOWORD(lParam);
|
||||
|
@ -461,6 +462,8 @@ LRESULT CALLBACK GraphicsWndProc(HWND hwnd, UINT msg, WPARAM wParam,
|
|||
|
||||
if(msg == WM_LBUTTONDOWN) {
|
||||
SS.GW.MouseLeftDown(x, y);
|
||||
} else if(msg == WM_LBUTTONUP) {
|
||||
SS.GW.MouseLeftUp(x, y);
|
||||
} else if(msg == WM_LBUTTONDBLCLK) {
|
||||
SS.GW.MouseLeftDoubleClick(x, y);
|
||||
} else if(msg == WM_MBUTTONDOWN) {
|
||||
|
|
Loading…
Reference in New Issue