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
Jonathan Westhues 2008-04-22 02:53:42 -08:00
parent 1f77024771
commit fa71238def
7 changed files with 158 additions and 57 deletions

View File

@ -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;

View File

@ -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();

View File

@ -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);

View File

@ -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();

View File

@ -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
View File

@ -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);

View File

@ -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) {