Now I can add a constraint (a length), and it's displayed
on-screen, and I can drag the label. That's progress. Also implement a bunch of untested expression stuff, since I'll need that for the values of the dimensions, for example. [git-p4: depot-paths = "//depot/solvespace/": change = 1668]solver
parent
094e10204d
commit
22302dca7a
2
Makefile
2
Makefile
|
@ -17,6 +17,8 @@ SSOBJS = $(OBJDIR)\solvespace.obj \
|
|||
$(OBJDIR)\sketch.obj \
|
||||
$(OBJDIR)\glhelper.obj \
|
||||
$(OBJDIR)\expr.obj \
|
||||
$(OBJDIR)\constraint.obj \
|
||||
$(OBJDIR)\drawconstraint.obj \
|
||||
|
||||
|
||||
LIBS = user32.lib gdi32.lib comctl32.lib advapi32.lib opengl32.lib glu32.lib
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
#include "solvespace.h"
|
||||
|
||||
hConstraint Constraint::AddConstraint(Constraint *c) {
|
||||
SS.constraint.AddAndAssignId(c);
|
||||
return c->h;
|
||||
}
|
||||
|
||||
void Constraint::MenuConstrain(int id) {
|
||||
Constraint c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
c.group = SS.GW.activeGroup;
|
||||
|
||||
SS.GW.GroupSelection();
|
||||
#define gs (SS.GW.gs)
|
||||
|
||||
switch(id) {
|
||||
case GraphicsWindow::MNU_DISTANCE_DIA:
|
||||
if(gs.points == 2 && gs.n == 2) {
|
||||
c.type = PT_PT_DISTANCE;
|
||||
c.ptA = gs.point[0];
|
||||
c.ptB = gs.point[1];
|
||||
} else if(gs.lineSegments == 1 && gs.n == 1) {
|
||||
c.type = PT_PT_DISTANCE;
|
||||
c.ptA = gs.entity[0].point(16);
|
||||
c.ptB = gs.entity[0].point(16+3);
|
||||
} else {
|
||||
Error("Bad selection for distance / diameter constraint.");
|
||||
return;
|
||||
}
|
||||
c.disp.offset = Vector::MakeFrom(50, 50, 50);
|
||||
AddConstraint(&c);
|
||||
break;
|
||||
|
||||
default: oops();
|
||||
}
|
||||
|
||||
SS.GW.ClearSelection();
|
||||
InvalidateGraphics();
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
#include "solvespace.h"
|
||||
|
||||
bool Constraint::HasLabel(void) {
|
||||
switch(type) {
|
||||
case PT_PT_DISTANCE:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Constraint::DrawOrGetDistance(void) {
|
||||
// Unit vectors that describe our current view of the scene.
|
||||
Vector gr = SS.GW.projRight;
|
||||
Vector gu = SS.GW.projUp;
|
||||
Vector gn = gr.Cross(gu);
|
||||
|
||||
switch(type) {
|
||||
case PT_PT_DISTANCE: {
|
||||
Vector ap = SS.GetPoint(ptA)->GetCoords();
|
||||
Vector bp = SS.GetPoint(ptB)->GetCoords();
|
||||
|
||||
Vector ref = ((ap.Plus(bp)).ScaledBy(0.5)).Plus(disp.offset);
|
||||
|
||||
if(dogd.drawing) {
|
||||
Vector ab = ap.Minus(bp);
|
||||
Vector ar = ap.Minus(ref);
|
||||
// Normal to a plan containing the line and the label origin.
|
||||
Vector n = ab.Cross(ar);
|
||||
Vector out = ab.Cross(n).WithMagnitude(1);
|
||||
out = out.ScaledBy(-out.Dot(ar));
|
||||
|
||||
glBegin(GL_LINES);
|
||||
glxVertex3v(ap);
|
||||
glxVertex3v(ap.Plus(out));
|
||||
glxVertex3v(bp);
|
||||
glxVertex3v(bp.Plus(out));
|
||||
glEnd();
|
||||
|
||||
glPushMatrix();
|
||||
glxTranslatev(ref);
|
||||
glxOntoCsys(gr, gu);
|
||||
glxWriteText("ABCDEFG");
|
||||
glPopMatrix();
|
||||
} else {
|
||||
Point2d o = SS.GW.ProjectPoint(ref);
|
||||
dogd.dmin = o.DistanceTo(dogd.mp) - 10;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: oops();
|
||||
}
|
||||
}
|
||||
|
||||
void Constraint::Draw(void) {
|
||||
dogd.drawing = true;
|
||||
DrawOrGetDistance();
|
||||
}
|
||||
|
||||
double Constraint::GetDistance(Point2d mp) {
|
||||
dogd.drawing = false;
|
||||
dogd.mp = mp;
|
||||
dogd.dmin = 1e12;
|
||||
|
||||
DrawOrGetDistance();
|
||||
|
||||
return dogd.dmin;
|
||||
}
|
||||
|
10
dsc.h
10
dsc.h
|
@ -19,6 +19,7 @@ public:
|
|||
Vector Normal(int which);
|
||||
Vector RotatedAbout(Vector axis, double theta);
|
||||
double Magnitude(void);
|
||||
Vector WithMagnitude(double s);
|
||||
Vector ScaledBy(double s);
|
||||
|
||||
// Call a rotation matrix [ u' v' n' ]'; this returns the first and
|
||||
|
@ -103,6 +104,15 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void Tag(H h, int tag) {
|
||||
int i;
|
||||
for(i = 0; i < elems; i++) {
|
||||
if(elem[i].t.h.v == h.v) {
|
||||
elem[i].tag = tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RemoveTagged(void) {
|
||||
int src, dest;
|
||||
dest = 0;
|
||||
|
|
70
expr.cpp
70
expr.cpp
|
@ -44,3 +44,73 @@ double Expr::Eval(void) {
|
|||
}
|
||||
}
|
||||
|
||||
Expr *Expr::PartialWrt(hParam p) {
|
||||
Expr *da, *db;
|
||||
|
||||
switch(op) {
|
||||
case PARAM_PTR: oops();
|
||||
case PARAM: return FromConstant(p.v == x.parh.v ? 1 : 0);
|
||||
|
||||
case CONSTANT: return FromConstant(0);
|
||||
|
||||
case PLUS: return (a->PartialWrt(p))->Plus(b->PartialWrt(p));
|
||||
case MINUS: return (a->PartialWrt(p))->Minus(b->PartialWrt(p));
|
||||
|
||||
case TIMES:
|
||||
da = a->PartialWrt(p);
|
||||
db = b->PartialWrt(p);
|
||||
return (a->Times(db))->Plus(b->Times(da));
|
||||
|
||||
case DIV:
|
||||
da = a->PartialWrt(p);
|
||||
db = b->PartialWrt(p);
|
||||
return ((da->Times(b))->Minus(a->Times(db)))->Div(b->Square());
|
||||
|
||||
case SQRT:
|
||||
return (FromConstant(0.5)->Div(a->Sqrt()))->Times(a->PartialWrt(p));
|
||||
|
||||
case SQUARE:
|
||||
return (FromConstant(2.0)->Times(a))->Times(a->PartialWrt(p));
|
||||
|
||||
case NEGATE: return (a->PartialWrt(p))->Negate();
|
||||
case SIN: return (a->Cos())->Times(a->PartialWrt(p));
|
||||
case COS: return ((a->Sin())->Times(a->PartialWrt(p)))->Negate();
|
||||
|
||||
default: oops();
|
||||
}
|
||||
}
|
||||
|
||||
static char StringBuffer[4096];
|
||||
void Expr::App(char *s, ...) {
|
||||
va_list f;
|
||||
va_start(f, s);
|
||||
vsprintf(StringBuffer+strlen(StringBuffer), s, f);
|
||||
}
|
||||
char *Expr::Print(void) {
|
||||
StringBuffer[0] = '\0';
|
||||
PrintW();
|
||||
return StringBuffer;
|
||||
}
|
||||
|
||||
void Expr::PrintW(void) {
|
||||
switch(op) {
|
||||
case PARAM: App("(param %08x)", x.parh.v); break;
|
||||
case PARAM_PTR: App("(paramp %08x)", x.parp->h.v); break;
|
||||
|
||||
case CONSTANT: App("%.3f", x.v);
|
||||
|
||||
case PLUS: App("(+ "); a->PrintW(); b->PrintW(); App(")"); break;
|
||||
case MINUS: App("(- "); a->PrintW(); b->PrintW(); App(")"); break;
|
||||
case TIMES: App("(* "); a->PrintW(); b->PrintW(); App(")"); break;
|
||||
case DIV: App("(/ "); a->PrintW(); b->PrintW(); App(")"); break;
|
||||
|
||||
case NEGATE: App("(- "); a->PrintW(); App(")"); break;
|
||||
case SQRT: App("(sqrt "); a->PrintW(); App(")"); break;
|
||||
case SQUARE: App("(square "); a->PrintW(); App(")"); break;
|
||||
case SIN: App("(sin "); a->PrintW(); App(")"); break;
|
||||
case COS: App("(cos "); a->PrintW(); App(")"); break;
|
||||
|
||||
default: oops();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
5
expr.h
5
expr.h
|
@ -58,7 +58,10 @@ public:
|
|||
double Eval(void);
|
||||
|
||||
void ParamsToPointers(void);
|
||||
void Print(void);
|
||||
|
||||
void App(char *str, ...);
|
||||
char *Print(void);
|
||||
void PrintW(void); // worker
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
119
graphicswin.cpp
119
graphicswin.cpp
|
@ -5,6 +5,7 @@
|
|||
#define mView (&GraphicsWindow::MenuView)
|
||||
#define mEdit (&GraphicsWindow::MenuEdit)
|
||||
#define mReq (&GraphicsWindow::MenuRequest)
|
||||
#define mCon (&Constraint::MenuConstrain)
|
||||
#define S 0x100
|
||||
const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
|
||||
{ 0, "&File", 0, NULL },
|
||||
|
@ -19,6 +20,8 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
|
|||
{ 1, "&Undo\tCtrl+Z", 0, NULL },
|
||||
{ 1, "&Redo\tCtrl+Y", 0, NULL },
|
||||
{ 1, NULL, 0, NULL },
|
||||
{ 1, "&Delete\tDel", MNU_DELETE, 127, mEdit },
|
||||
{ 1, NULL, 0, NULL },
|
||||
{ 1, "&Unselect All\tEsc", MNU_UNSELECT_ALL, 27, mEdit },
|
||||
|
||||
{ 0, "&View", 0, NULL },
|
||||
|
@ -27,7 +30,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
|
|||
{ 1, "Zoom To &Fit\tF", MNU_ZOOM_TO_FIT, 'F', mView },
|
||||
{ 1, NULL, 0, NULL },
|
||||
{ 1, "&Onto Plane / Coordinate System\tO", MNU_ORIENT_ONTO, 'O', mView },
|
||||
{ 1, "&Lock Orientation\tL", 0, 'L', mView },
|
||||
{ 1, "&Lock Orientation\tL", MNU_LOCK_VIEW, 'L', mView },
|
||||
{ 1, NULL, 0, NULL },
|
||||
{ 1, "Dimensions in &Inches", 0, NULL },
|
||||
{ 1, "Dimensions in &Millimeters", 0, NULL },
|
||||
|
@ -54,7 +57,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
|
|||
{ 1, "To&ggle Construction\tG", 0, 'G', NULL },
|
||||
|
||||
{ 0, "&Constrain", 0, NULL },
|
||||
{ 1, "&Distance / Diameter\tShift+D", 0, 'D'|S, NULL },
|
||||
{ 1, "&Distance / Diameter\tShift+D", MNU_DISTANCE_DIA, 'D'|S, mCon },
|
||||
{ 1, "A&ngle\tShift+N", 0, 'N'|S, NULL },
|
||||
{ 1, "Other S&upplementary Angle\tShift+U", 0, 'U'|S, NULL },
|
||||
{ 1, NULL, 0, NULL },
|
||||
|
@ -108,7 +111,7 @@ Point2d GraphicsWindow::ProjectPoint(Vector p) {
|
|||
return r;
|
||||
}
|
||||
|
||||
void GraphicsWindow::MenuView(MenuId id) {
|
||||
void GraphicsWindow::MenuView(int id) {
|
||||
switch(id) {
|
||||
case MNU_ZOOM_IN:
|
||||
SS.GW.scale *= 1.2;
|
||||
|
@ -121,6 +124,11 @@ void GraphicsWindow::MenuView(MenuId id) {
|
|||
case MNU_ZOOM_TO_FIT:
|
||||
break;
|
||||
|
||||
case MNU_LOCK_VIEW:
|
||||
SS.GW.viewLocked = !SS.GW.viewLocked;
|
||||
CheckMenuById(MNU_LOCK_VIEW, SS.GW.viewLocked);
|
||||
break;
|
||||
|
||||
case MNU_ORIENT_ONTO:
|
||||
SS.GW.GroupSelection();
|
||||
if(SS.GW.gs.n == 1 && SS.GW.gs.csyss == 1) {
|
||||
|
@ -155,7 +163,7 @@ void GraphicsWindow::EnsureValidActiveGroup(void) {
|
|||
activeGroup = SS.group.elem[i].t.h;
|
||||
}
|
||||
|
||||
void GraphicsWindow::MenuEdit(MenuId id) {
|
||||
void GraphicsWindow::MenuEdit(int id) {
|
||||
switch(id) {
|
||||
case MNU_UNSELECT_ALL:
|
||||
SS.GW.ClearSelection();
|
||||
|
@ -164,11 +172,38 @@ void GraphicsWindow::MenuEdit(MenuId id) {
|
|||
SS.TW.Show();
|
||||
break;
|
||||
|
||||
case MNU_DELETE: {
|
||||
int i;
|
||||
SS.request.ClearTags();
|
||||
for(i = 0; i < MAX_SELECTED; i++) {
|
||||
Selection *s = &(SS.GW.selection[i]);
|
||||
hRequest r;
|
||||
r.v = 0;
|
||||
if(s->point.v) {
|
||||
Point *pt = SS.GetPoint(s->point);
|
||||
Entity *e = SS.GetEntity(pt->entity());
|
||||
if(e->type == Entity::DATUM_POINT) {
|
||||
r = e->request();
|
||||
}
|
||||
} else if(s->entity.v) {
|
||||
Entity *e = SS.GetEntity(s->entity);
|
||||
r = e->request();
|
||||
}
|
||||
if(r.v) SS.request.Tag(r, 1);
|
||||
}
|
||||
SS.request.RemoveTagged();
|
||||
|
||||
SS.GenerateAll();
|
||||
SS.GW.ClearSelection();
|
||||
SS.GW.hover.Clear();
|
||||
break;
|
||||
}
|
||||
|
||||
default: oops();
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsWindow::MenuRequest(MenuId id) {
|
||||
void GraphicsWindow::MenuRequest(int id) {
|
||||
char *s;
|
||||
switch(id) {
|
||||
case MNU_DATUM_POINT: s = "click to place datum point"; goto c;
|
||||
|
@ -183,12 +218,16 @@ c:
|
|||
}
|
||||
}
|
||||
|
||||
void GraphicsWindow::UpdateDraggedPoint(hPoint hp, double mx, double my) {
|
||||
void GraphicsWindow::UpdateDraggedHPoint(hPoint hp, double mx, double my) {
|
||||
Point *p = SS.point.FindById(hp);
|
||||
Vector pos = p->GetCoords();
|
||||
pos = pos.Plus(projRight.ScaledBy((mx - orig.mouse.x)/scale));
|
||||
pos = pos.Plus(projUp.ScaledBy((my - orig.mouse.y)/scale));
|
||||
UpdateDraggedPoint(&pos, mx, my);
|
||||
p->ForceTo(pos);
|
||||
}
|
||||
|
||||
void GraphicsWindow::UpdateDraggedPoint(Vector *pos, double mx, double my) {
|
||||
*pos = pos->Plus(projRight.ScaledBy((mx - orig.mouse.x)/scale));
|
||||
*pos = pos->Plus(projUp.ScaledBy((my - orig.mouse.y)/scale));
|
||||
|
||||
orig.mouse.x = mx;
|
||||
orig.mouse.y = my;
|
||||
|
@ -206,11 +245,12 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
|||
double dx = (x - orig.mouse.x) / scale;
|
||||
double dy = (y - orig.mouse.y) / scale;
|
||||
|
||||
if(shiftDown) {
|
||||
// When the view is locked, permit only translation (pan).
|
||||
if(shiftDown || viewLocked) {
|
||||
offset.x = orig.offset.x + dx*projRight.x + dy*projUp.x;
|
||||
offset.y = orig.offset.y + dx*projRight.y + dy*projUp.y;
|
||||
offset.z = orig.offset.z + dx*projRight.z + dy*projUp.z;
|
||||
} else if(ctrlDown) {
|
||||
} else if(ctrlDown && !viewLocked) {
|
||||
double theta = atan2(orig.mouse.y, orig.mouse.x);
|
||||
theta -= atan2(y, x);
|
||||
|
||||
|
@ -219,7 +259,7 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
|||
projUp = orig.projUp.RotatedAbout(normal, theta);
|
||||
|
||||
NormalizeProjectionVectors();
|
||||
} else {
|
||||
} else if(!viewLocked) {
|
||||
double s = 0.3*(PI/180); // degrees per pixel
|
||||
projRight = orig.projRight.RotatedAbout(orig.projUp, -s*dx);
|
||||
projUp = orig.projUp.RotatedAbout(orig.projRight, s*dy);
|
||||
|
@ -235,14 +275,21 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
|||
|
||||
InvalidateGraphics();
|
||||
} else if(leftDown) {
|
||||
// We are left-dragging. This is often used to drag points.
|
||||
// We are left-dragging. This is often used to drag points, or
|
||||
// constraint labels.
|
||||
if(hover.point.v && !hover.point.isFromReferences()) {
|
||||
ClearSelection();
|
||||
UpdateDraggedPoint(hover.point, x, y);
|
||||
UpdateDraggedHPoint(hover.point, x, y);
|
||||
} else if(hover.constraint.v &&
|
||||
SS.GetConstraint(hover.constraint)->HasLabel())
|
||||
{
|
||||
ClearSelection();
|
||||
Constraint *c = SS.constraint.FindById(hover.constraint);
|
||||
UpdateDraggedPoint(&(c->disp.offset), x, y);
|
||||
}
|
||||
} else {
|
||||
if(pendingOperation == PENDING_OPERATION_DRAGGING_POINT) {
|
||||
UpdateDraggedPoint(pendingPoint, x, y);
|
||||
UpdateDraggedHPoint(pendingPoint, x, y);
|
||||
} else {
|
||||
// Do our usual hit testing, for the selection.
|
||||
Selection s;
|
||||
|
@ -256,35 +303,37 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
|||
}
|
||||
|
||||
bool GraphicsWindow::Selection::Equals(Selection *b) {
|
||||
if(point.v != b->point.v) return false;
|
||||
if(entity.v != b->entity.v) return false;
|
||||
if(point.v != b->point.v) return false;
|
||||
if(entity.v != b->entity.v) return false;
|
||||
if(constraint.v != b->constraint.v) return false;
|
||||
return true;
|
||||
}
|
||||
bool GraphicsWindow::Selection::IsEmpty(void) {
|
||||
if(point.v) return false;
|
||||
if(entity.v) return false;
|
||||
if(point.v) return false;
|
||||
if(entity.v) return false;
|
||||
if(constraint.v) return false;
|
||||
return true;
|
||||
}
|
||||
void GraphicsWindow::Selection::Clear(void) {
|
||||
point.v = entity.v = 0;
|
||||
point.v = entity.v = constraint.v = 0;
|
||||
}
|
||||
void GraphicsWindow::Selection::Draw(void) {
|
||||
if(point.v) SS.point. FindById(point )->Draw();
|
||||
if(entity.v) SS.entity.FindById(entity)->Draw();
|
||||
if(point.v) SS.point. FindById(point )->Draw();
|
||||
if(entity.v) SS.entity. FindById(entity )->Draw();
|
||||
if(constraint.v) SS.constraint.FindById(constraint)->Draw();
|
||||
}
|
||||
|
||||
void GraphicsWindow::HitTestMakeSelection(Point2d mp, Selection *dest) {
|
||||
int i;
|
||||
double d, dmin = 1e12;
|
||||
|
||||
dest->point.v = 0;
|
||||
dest->entity.v = 0;
|
||||
memset(dest, 0, sizeof(*dest));
|
||||
|
||||
// Do the points
|
||||
for(i = 0; i < SS.entity.elems; i++) {
|
||||
d = SS.entity.elem[i].t.GetDistance(mp);
|
||||
if(d < 10 && d < dmin) {
|
||||
dest->point.v = 0;
|
||||
memset(dest, 0, sizeof(*dest));
|
||||
dest->entity = SS.entity.elem[i].t.h;
|
||||
}
|
||||
}
|
||||
|
@ -293,10 +342,19 @@ void GraphicsWindow::HitTestMakeSelection(Point2d mp, Selection *dest) {
|
|||
for(i = 0; i < SS.point.elems; i++) {
|
||||
d = SS.point.elem[i].t.GetDistance(mp);
|
||||
if(d < 10 && d < dmin) {
|
||||
dest->entity.v = 0;
|
||||
memset(dest, 0, sizeof(*dest));
|
||||
dest->point = SS.point.elem[i].t.h;
|
||||
}
|
||||
}
|
||||
|
||||
// Constraints
|
||||
for(i = 0; i < SS.constraint.elems; i++) {
|
||||
d = SS.constraint.elem[i].t.GetDistance(mp);
|
||||
if(d < 10 && d < dmin) {
|
||||
memset(dest, 0, sizeof(*dest));
|
||||
dest->constraint = SS.constraint.elem[i].t.h;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsWindow::ClearSelection(void) {
|
||||
|
@ -308,7 +366,7 @@ void GraphicsWindow::ClearSelection(void) {
|
|||
|
||||
void GraphicsWindow::GroupSelection(void) {
|
||||
gs.points = gs.entities = 0;
|
||||
gs.csyss = 0;
|
||||
gs.csyss = gs.lineSegments = 0;
|
||||
gs.n = 0;
|
||||
int i;
|
||||
for(i = 0; i < MAX_SELECTED; i++) {
|
||||
|
@ -322,8 +380,9 @@ void GraphicsWindow::GroupSelection(void) {
|
|||
(gs.n)++;
|
||||
|
||||
Entity *e = SS.entity.FindById(s->entity);
|
||||
if(e->type == Entity::CSYS_2D) {
|
||||
(gs.csyss)++;
|
||||
switch(e->type) {
|
||||
case Entity::CSYS_2D: (gs.csyss)++; break;
|
||||
case Entity::LINE_SEGMENT: (gs.lineSegments)++; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -496,6 +555,10 @@ void GraphicsWindow::Paint(int w, int h) {
|
|||
for(i = 0; i < SS.point.elems; i++) {
|
||||
SS.point.elem[i].t.Draw();
|
||||
}
|
||||
glColor3f(1.0f, 0, 1.0f);
|
||||
for(i = 0; i < SS.constraint.elems; i++) {
|
||||
SS.constraint.elem[i].t.Draw();
|
||||
}
|
||||
|
||||
// Then redraw whatever the mouse is hovering over, highlighted. Have
|
||||
// to disable the depth test, so that we can overdraw.
|
||||
|
|
72
sketch.h
72
sketch.h
|
@ -12,6 +12,9 @@ class Entity;
|
|||
class Param;
|
||||
class Point;
|
||||
|
||||
class hEquation;
|
||||
class Equation;
|
||||
|
||||
// All of the hWhatever handles are a 32-bit ID, that is used to represent
|
||||
// some data structure in the sketch.
|
||||
class hGroup {
|
||||
|
@ -79,9 +82,9 @@ public:
|
|||
static const hRequest HREQUEST_REFERENCE_ZX;
|
||||
|
||||
// Types of requests
|
||||
static const int CSYS_2D = 0;
|
||||
static const int DATUM_POINT = 1;
|
||||
static const int LINE_SEGMENT = 10;
|
||||
static const int CSYS_2D = 10;
|
||||
static const int DATUM_POINT = 11;
|
||||
static const int LINE_SEGMENT = 20;
|
||||
|
||||
int type;
|
||||
|
||||
|
@ -173,6 +176,69 @@ public:
|
|||
double GetDistance(Point2d mp);
|
||||
};
|
||||
|
||||
class hConstraint {
|
||||
public:
|
||||
DWORD v;
|
||||
};
|
||||
|
||||
class Constraint {
|
||||
public:
|
||||
static const int USER_EQUATION = 10;
|
||||
static const int POINTS_COINCIDENT = 20;
|
||||
static const int PT_PT_DISTANCE = 30;
|
||||
static const int PT_LINE_DISTANCE = 31;
|
||||
|
||||
static const int HORIZONTAL = 40;
|
||||
static const int VERTICAL = 41;
|
||||
|
||||
hConstraint h;
|
||||
int type;
|
||||
hGroup group;
|
||||
|
||||
// These are the parameters for the constraint.
|
||||
Expr *exprA;
|
||||
Expr *exprB;
|
||||
hPoint ptA;
|
||||
hPoint ptB;
|
||||
hPoint ptC;
|
||||
hEntity entityA;
|
||||
hEntity entityB;
|
||||
|
||||
// These define how the constraint is drawn on-screen.
|
||||
struct {
|
||||
hEntity csys;
|
||||
Vector offset;
|
||||
Vector u, v;
|
||||
} disp;
|
||||
|
||||
static hConstraint AddConstraint(Constraint *c);
|
||||
static void MenuConstrain(int id);
|
||||
|
||||
struct {
|
||||
bool drawing;
|
||||
Point2d mp;
|
||||
double dmin;
|
||||
} dogd; // state for drawing or getting distance (for hit testing)
|
||||
double GetDistance(Point2d mp);
|
||||
void Draw(void);
|
||||
void DrawOrGetDistance(void);
|
||||
|
||||
bool HasLabel(void);
|
||||
|
||||
void Generate(IdList<Equation,hEquation> *l);
|
||||
};
|
||||
|
||||
class hEquation {
|
||||
public:
|
||||
DWORD v;
|
||||
};
|
||||
|
||||
class Equation {
|
||||
public:
|
||||
hEquation h;
|
||||
Expr *e;
|
||||
};
|
||||
|
||||
|
||||
inline hEntity hRequest::entity(int i)
|
||||
{ hEntity r; r.v = (v << 10) | i; return r; }
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
#include "solvespace.h"
|
||||
|
||||
template IdList<Request,hRequest>;
|
||||
template IdList<Entity,hEntity>;
|
||||
template IdList<Point,hPoint>;
|
||||
|
||||
SolveSpace SS;
|
||||
|
||||
void SolveSpace::Init(void) {
|
||||
constraint.Clear();
|
||||
request.Clear();
|
||||
group.Clear();
|
||||
|
||||
entity.Clear();
|
||||
point.Clear();
|
||||
param.Clear();
|
||||
group.Clear();
|
||||
|
||||
// Our initial group, that contains the references.
|
||||
Group g;
|
||||
|
|
44
solvespace.h
44
solvespace.h
|
@ -12,13 +12,6 @@
|
|||
#define max(x, y) ((x) > (y) ? (x) : (y))
|
||||
#endif
|
||||
|
||||
class Expr;
|
||||
|
||||
void dbp(char *str, ...);
|
||||
void Error(char *str, ...);
|
||||
Expr *AllocExpr(void);
|
||||
void FreeAllExprs(void);
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
@ -27,14 +20,23 @@ void FreeAllExprs(void);
|
|||
#include <gl/gl.h>
|
||||
#include <gl/glu.h>
|
||||
|
||||
class Expr;
|
||||
|
||||
// From the platform-specific code.
|
||||
void CheckMenuById(int id, BOOL checked);
|
||||
void InvalidateGraphics(void);
|
||||
void InvalidateText(void);
|
||||
void dbp(char *str, ...);
|
||||
void Error(char *str, ...);
|
||||
Expr *AllocExpr(void);
|
||||
void FreeAllExprs(void);
|
||||
|
||||
|
||||
#include "dsc.h"
|
||||
#include "sketch.h"
|
||||
#include "ui.h"
|
||||
#include "expr.h"
|
||||
|
||||
// From the platform-specific code.
|
||||
void InvalidateGraphics(void);
|
||||
void InvalidateText(void);
|
||||
|
||||
// Utility functions that are provided in the platform-independent code.
|
||||
void glxVertex3v(Vector u);
|
||||
|
@ -56,14 +58,22 @@ public:
|
|||
TextWindow TW;
|
||||
GraphicsWindow GW;
|
||||
|
||||
IdList<Group,hGroup> group;
|
||||
IdList<Request,hRequest> request;
|
||||
IdList<Entity,hEntity> entity;
|
||||
IdList<Point,hPoint> point;
|
||||
IdList<Param,hParam> param;
|
||||
// These lists define the sketch, and are edited by the user.
|
||||
IdList<Group,hGroup> group;
|
||||
IdList<Request,hRequest> request;
|
||||
IdList<Constraint,hConstraint> constraint;
|
||||
|
||||
inline Entity *GetEntity(hEntity h) { return entity.FindById(h); }
|
||||
inline Param *GetParam (hParam h) { return param. FindById(h); }
|
||||
// These lists are generated automatically when we solve the sketch.
|
||||
IdList<Entity,hEntity> entity;
|
||||
IdList<Point,hPoint> point;
|
||||
IdList<Param,hParam> param;
|
||||
|
||||
inline Constraint *GetConstraint(hConstraint h)
|
||||
{ return constraint.FindById(h); }
|
||||
inline Request *GetRequest(hRequest h) { return request.FindById(h); }
|
||||
inline Entity *GetEntity (hEntity h) { return entity. FindById(h); }
|
||||
inline Param *GetParam (hParam h) { return param. FindById(h); }
|
||||
inline Point *GetPoint (hPoint h) { return point. FindById(h); }
|
||||
|
||||
hGroup activeGroup;
|
||||
|
||||
|
|
19
ui.h
19
ui.h
|
@ -78,12 +78,17 @@ public:
|
|||
MNU_ZOOM_OUT,
|
||||
MNU_ZOOM_TO_FIT,
|
||||
MNU_ORIENT_ONTO,
|
||||
MNU_LOCK_VIEW,
|
||||
MNU_UNSELECT_ALL,
|
||||
// Edit
|
||||
MNU_DELETE,
|
||||
// Request
|
||||
MNU_DATUM_POINT,
|
||||
MNU_LINE_SEGMENT,
|
||||
// Constrain
|
||||
MNU_DISTANCE_DIA,
|
||||
} MenuId;
|
||||
typedef void MenuHandler(MenuId id);
|
||||
typedef void MenuHandler(int id);
|
||||
typedef struct {
|
||||
int level; // 0 == on menu bar, 1 == one level down
|
||||
char *label; // or NULL for a separator
|
||||
|
@ -92,9 +97,9 @@ public:
|
|||
MenuHandler *fn;
|
||||
} MenuEntry;
|
||||
static const MenuEntry menu[];
|
||||
static void MenuView(MenuId id);
|
||||
static void MenuEdit(MenuId id);
|
||||
static void MenuRequest(MenuId id);
|
||||
static void MenuView(int id);
|
||||
static void MenuEdit(int id);
|
||||
static void MenuRequest(int id);
|
||||
|
||||
// The width and height (in pixels) of the window.
|
||||
double width, height;
|
||||
|
@ -111,6 +116,7 @@ public:
|
|||
Vector projUp;
|
||||
Point2d mouse;
|
||||
} orig;
|
||||
bool viewLocked;
|
||||
|
||||
void NormalizeProjectionVectors(void);
|
||||
Point2d ProjectPoint(Vector p);
|
||||
|
@ -132,6 +138,7 @@ public:
|
|||
public:
|
||||
hPoint point;
|
||||
hEntity entity;
|
||||
hConstraint constraint;
|
||||
|
||||
void Draw(void);
|
||||
|
||||
|
@ -150,6 +157,7 @@ public:
|
|||
int points;
|
||||
int entities;
|
||||
int csyss;
|
||||
int lineSegments;
|
||||
int n;
|
||||
} gs;
|
||||
void GroupSelection(void);
|
||||
|
@ -163,7 +171,8 @@ public:
|
|||
static void ToggleBool(int link, DWORD v);
|
||||
static void ToggleAnyDatumShown(int link, DWORD v);
|
||||
|
||||
void UpdateDraggedPoint(hPoint hp, double mx, double my);
|
||||
void UpdateDraggedPoint(Vector *pos, double mx, double my);
|
||||
void UpdateDraggedHPoint(hPoint hp, double mx, double my);
|
||||
|
||||
// These are called by the platform-specific code.
|
||||
void Paint(int w, int h);
|
||||
|
|
11
util.cpp
11
util.cpp
|
@ -120,7 +120,7 @@ Vector Vector::Normal(int which) {
|
|||
oops();
|
||||
}
|
||||
|
||||
n = n.ScaledBy(1/n.Magnitude());
|
||||
n = n.WithMagnitude(1);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
@ -160,6 +160,15 @@ Vector Vector::ScaledBy(double v) {
|
|||
return r;
|
||||
}
|
||||
|
||||
Vector Vector::WithMagnitude(double v) {
|
||||
double m = Magnitude();
|
||||
if(m < 0.001) {
|
||||
return MakeFrom(v, 0, 0);
|
||||
} else {
|
||||
return ScaledBy(v/Magnitude());
|
||||
}
|
||||
}
|
||||
|
||||
Point2d Point2d::Plus(Point2d b) {
|
||||
Point2d r;
|
||||
r.x = x + b.x;
|
||||
|
|
|
@ -39,7 +39,6 @@ void dbp(char *str, ...)
|
|||
va_start(f, str);
|
||||
vsprintf(buf, str, f);
|
||||
OutputDebugString(buf);
|
||||
OutputDebugString("\n");
|
||||
}
|
||||
|
||||
void Error(char *str, ...)
|
||||
|
@ -300,8 +299,8 @@ static BOOL ProcessKeyDown(WPARAM wParam)
|
|||
c = wParam;
|
||||
break;
|
||||
}
|
||||
if(GetAsyncKeyState(VK_CONTROL) & 0x8000) c |= 0x100;
|
||||
if(GetAsyncKeyState(VK_SHIFT) & 0x8000) c |= 0x200;
|
||||
if(GetAsyncKeyState(VK_SHIFT) & 0x8000) c |= 0x100;
|
||||
if(GetAsyncKeyState(VK_CONTROL) & 0x8000) c |= 0x200;
|
||||
|
||||
for(int i = 0; SS.GW.menu[i].level >= 0; i++) {
|
||||
if(c == SS.GW.menu[i].accel) {
|
||||
|
@ -443,6 +442,26 @@ LRESULT CALLBACK GraphicsWndProc(HWND hwnd, UINT msg, WPARAM wParam,
|
|||
return 1;
|
||||
}
|
||||
|
||||
void CheckMenuById(int id, BOOL checked)
|
||||
{
|
||||
int i;
|
||||
int subMenu = -1;
|
||||
|
||||
for(i = 0; SS.GW.menu[i].level >= 0; i++) {
|
||||
if(SS.GW.menu[i].level == 0) subMenu++;
|
||||
|
||||
if(SS.GW.menu[i].id == id) {
|
||||
if(subMenu < 0) oops();
|
||||
if(subMenu >= (sizeof(SubMenus)/sizeof(SubMenus[0]))) oops();
|
||||
|
||||
CheckMenuItem(SubMenus[subMenu], id,
|
||||
checked ? MF_CHECKED : MF_UNCHECKED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
oops();
|
||||
}
|
||||
|
||||
HMENU CreateGraphicsWindowMenus(void)
|
||||
{
|
||||
HMENU top = CreateMenu();
|
||||
|
|
Loading…
Reference in New Issue