2008-03-26 09:18:12 +00:00
|
|
|
#include <stdarg.h>
|
2008-03-27 09:53:51 +00:00
|
|
|
|
|
|
|
#include "solvespace.h"
|
2008-03-26 09:18:12 +00:00
|
|
|
|
2008-04-12 15:17:58 +00:00
|
|
|
#define mView (&GraphicsWindow::MenuView)
|
|
|
|
#define mEdit (&GraphicsWindow::MenuEdit)
|
2008-04-13 10:57:41 +00:00
|
|
|
#define mReq (&GraphicsWindow::MenuRequest)
|
2008-04-14 10:28:32 +00:00
|
|
|
#define mCon (&Constraint::MenuConstrain)
|
2008-04-18 11:11:48 +00:00
|
|
|
#define mFile (&SolveSpace::MenuFile)
|
2008-04-13 10:57:41 +00:00
|
|
|
#define S 0x100
|
2008-04-18 11:11:48 +00:00
|
|
|
#define C 0x200
|
2008-03-26 09:18:12 +00:00
|
|
|
const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
|
2008-04-13 10:57:41 +00:00
|
|
|
{ 0, "&File", 0, NULL },
|
2008-04-18 11:11:48 +00:00
|
|
|
{ 1, "&New\tCtrl+N", MNU_NEW, 'N'|C, mFile },
|
|
|
|
{ 1, "&Open...\tCtrl+O", MNU_OPEN, 'O'|C, mFile },
|
|
|
|
{ 1, "&Save\tCtrl+S", MNU_SAVE, 'S'|C, mFile },
|
|
|
|
{ 1, "Save &As...", MNU_SAVE_AS, 0, mFile },
|
|
|
|
{ 1, NULL, 0, 0, NULL },
|
|
|
|
{ 1, "E&xit", MNU_EXIT, 0, mFile },
|
2008-04-13 10:57:41 +00:00
|
|
|
|
|
|
|
{ 0, "&Edit", 0, NULL },
|
|
|
|
{ 1, "&Undo\tCtrl+Z", 0, NULL },
|
|
|
|
{ 1, "&Redo\tCtrl+Y", 0, NULL },
|
|
|
|
{ 1, NULL, 0, NULL },
|
2008-04-14 10:28:32 +00:00
|
|
|
{ 1, "&Delete\tDel", MNU_DELETE, 127, mEdit },
|
|
|
|
{ 1, NULL, 0, NULL },
|
2008-04-13 10:57:41 +00:00
|
|
|
{ 1, "&Unselect All\tEsc", MNU_UNSELECT_ALL, 27, mEdit },
|
|
|
|
|
|
|
|
{ 0, "&View", 0, NULL },
|
|
|
|
{ 1, "Zoom &In\t+", MNU_ZOOM_IN, '+', mView },
|
|
|
|
{ 1, "Zoom &Out\t-", MNU_ZOOM_OUT, '-', mView },
|
|
|
|
{ 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 },
|
2008-04-14 10:28:32 +00:00
|
|
|
{ 1, "&Lock Orientation\tL", MNU_LOCK_VIEW, 'L', mView },
|
2008-04-13 10:57:41 +00:00
|
|
|
{ 1, NULL, 0, NULL },
|
|
|
|
{ 1, "Dimensions in &Inches", 0, NULL },
|
|
|
|
{ 1, "Dimensions in &Millimeters", 0, NULL },
|
|
|
|
|
|
|
|
{ 0, "&Request", 0, NULL },
|
2008-04-18 07:06:37 +00:00
|
|
|
{ 1, "Dra&w in 2d Coordinate System\tW", MNU_SEL_CSYS, 'W', mReq },
|
2008-04-18 11:11:48 +00:00
|
|
|
{ 1, "Draw Anywhere in 3d\tQ", MNU_NO_CSYS, 'Q', mReq },
|
2008-04-18 07:06:37 +00:00
|
|
|
{ 1, NULL, 0, NULL },
|
2008-04-13 10:57:41 +00:00
|
|
|
{ 1, "Datum &Point\tP", MNU_DATUM_POINT, 'P', mReq },
|
|
|
|
{ 1, "Datum A&xis\tX", 0, 'X', mReq },
|
|
|
|
{ 1, "Datum Pla&ne\tN", 0, 'N', mReq },
|
|
|
|
{ 1, "2d Coordinate S&ystem\tY", 0, 'Y', mReq },
|
|
|
|
{ 1, NULL, 0, NULL },
|
|
|
|
{ 1, "Line &Segment\tS", MNU_LINE_SEGMENT, 'S', 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 },
|
|
|
|
{ 1, "To&ggle Construction\tG", 0, 'G', NULL },
|
|
|
|
|
|
|
|
{ 0, "&Constrain", 0, NULL },
|
2008-04-14 10:28:32 +00:00
|
|
|
{ 1, "&Distance / Diameter\tShift+D", MNU_DISTANCE_DIA, 'D'|S, mCon },
|
2008-04-13 10:57:41 +00:00
|
|
|
{ 1, "A&ngle\tShift+N", 0, 'N'|S, NULL },
|
|
|
|
{ 1, "Other S&upplementary Angle\tShift+U", 0, 'U'|S, NULL },
|
|
|
|
{ 1, NULL, 0, NULL },
|
|
|
|
{ 1, "&Horizontal\tShift+H", 0, 'H'|S, NULL },
|
|
|
|
{ 1, "&Vertical\tShift+V", 0, 'V'|S, NULL },
|
|
|
|
{ 1, NULL, 0, NULL },
|
|
|
|
{ 1, "Coincident / &On Curve\tShift+O", 0, 'O'|S, NULL },
|
|
|
|
{ 1, "E&qual Length / Radius\tShift+Q", 0, 'Q'|S, NULL },
|
|
|
|
{ 1, "At &Midpoint\tShift+M", 0, 'M'|S, NULL },
|
|
|
|
{ 1, "S&ymmetric\tShift+Y", 0, 'Y'|S, NULL },
|
|
|
|
{ 1, NULL, 0, NULL },
|
|
|
|
{ 1, "Sym&bolic Equation\tShift+B", 0, 'B'|S, NULL },
|
2008-04-20 11:35:10 +00:00
|
|
|
{ 1, NULL, 0, NULL },
|
|
|
|
{ 1, "Solve Once Now\tSpace", MNU_SOLVE_NOW, ' ', mCon },
|
2008-04-13 10:57:41 +00:00
|
|
|
|
|
|
|
{ 0, "&Help", 0, NULL },
|
|
|
|
{ 1, "&About\t", 0, NULL },
|
2008-04-12 15:17:58 +00:00
|
|
|
{ -1 },
|
2008-03-26 09:18:12 +00:00
|
|
|
};
|
|
|
|
|
2008-03-27 09:53:51 +00:00
|
|
|
void GraphicsWindow::Init(void) {
|
2008-04-12 14:12:26 +00:00
|
|
|
memset(this, 0, sizeof(*this));
|
|
|
|
|
|
|
|
offset.x = offset.y = offset.z = 0;
|
2008-03-27 09:53:51 +00:00
|
|
|
scale = 1;
|
|
|
|
projRight.x = 1; projRight.y = projRight.z = 0;
|
2008-04-12 15:17:58 +00:00
|
|
|
projUp.y = 1; projUp.z = projUp.x = 0;
|
2008-03-27 09:53:51 +00:00
|
|
|
|
2008-04-18 07:06:37 +00:00
|
|
|
EnsureValidActives();
|
2008-04-13 10:57:41 +00:00
|
|
|
|
2008-04-11 12:47:14 +00:00
|
|
|
show2dCsyss = true;
|
|
|
|
showAxes = true;
|
|
|
|
showPoints = true;
|
|
|
|
showAllGroups = true;
|
|
|
|
showConstraints = true;
|
2008-03-27 09:53:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GraphicsWindow::NormalizeProjectionVectors(void) {
|
2008-04-12 15:17:58 +00:00
|
|
|
Vector norm = projRight.Cross(projUp);
|
|
|
|
projUp = norm.Cross(projRight);
|
2008-03-27 09:53:51 +00:00
|
|
|
|
2008-04-12 15:17:58 +00:00
|
|
|
projUp = projUp.ScaledBy(1/projUp.Magnitude());
|
2008-03-27 09:53:51 +00:00
|
|
|
projRight = projRight.ScaledBy(1/projRight.Magnitude());
|
|
|
|
}
|
|
|
|
|
2008-04-12 14:12:26 +00:00
|
|
|
Point2d GraphicsWindow::ProjectPoint(Vector p) {
|
|
|
|
p = p.Plus(offset);
|
|
|
|
|
|
|
|
Point2d r;
|
|
|
|
r.x = p.Dot(projRight) * scale;
|
2008-04-12 15:17:58 +00:00
|
|
|
r.y = p.Dot(projUp) * scale;
|
2008-04-12 14:12:26 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2008-04-14 10:28:32 +00:00
|
|
|
void GraphicsWindow::MenuView(int id) {
|
2008-04-12 15:17:58 +00:00
|
|
|
switch(id) {
|
|
|
|
case MNU_ZOOM_IN:
|
|
|
|
SS.GW.scale *= 1.2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MNU_ZOOM_OUT:
|
|
|
|
SS.GW.scale /= 1.2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MNU_ZOOM_TO_FIT:
|
|
|
|
break;
|
|
|
|
|
2008-04-14 10:28:32 +00:00
|
|
|
case MNU_LOCK_VIEW:
|
|
|
|
SS.GW.viewLocked = !SS.GW.viewLocked;
|
|
|
|
CheckMenuById(MNU_LOCK_VIEW, SS.GW.viewLocked);
|
|
|
|
break;
|
|
|
|
|
2008-04-18 11:11:48 +00:00
|
|
|
case MNU_ORIENT_ONTO: {
|
2008-04-12 15:17:58 +00:00
|
|
|
SS.GW.GroupSelection();
|
2008-04-18 11:11:48 +00:00
|
|
|
Entity *e = NULL;
|
2008-04-12 15:17:58 +00:00
|
|
|
if(SS.GW.gs.n == 1 && SS.GW.gs.csyss == 1) {
|
2008-04-19 11:09:47 +00:00
|
|
|
e = SS.GetEntity(SS.GW.gs.entity[0]);
|
2008-04-18 11:11:48 +00:00
|
|
|
} else if(SS.GW.activeCsys.v != Entity::NO_CSYS.v) {
|
2008-04-19 11:09:47 +00:00
|
|
|
e = SS.GetEntity(SS.GW.activeCsys);
|
2008-04-18 11:11:48 +00:00
|
|
|
}
|
|
|
|
if(e) {
|
|
|
|
// A quaternion with our original rotation
|
|
|
|
Quaternion quat0 = Quaternion::MakeFrom(
|
|
|
|
SS.GW.projRight, SS.GW.projUp);
|
|
|
|
// And with our final rotation
|
|
|
|
Vector pr, pu;
|
2008-04-19 11:44:44 +00:00
|
|
|
e->Csys2dGetBasisVectors(&pr, &pu);
|
2008-04-18 11:11:48 +00:00
|
|
|
Quaternion quatf = Quaternion::MakeFrom(pr, pu);
|
|
|
|
// Make sure we take the shorter of the two possible paths.
|
|
|
|
double mp = (quatf.Minus(quat0)).Magnitude();
|
|
|
|
double mm = (quatf.Plus(quat0)).Magnitude();
|
|
|
|
if(mp > mm) {
|
|
|
|
quatf = quatf.ScaledBy(-1);
|
|
|
|
mp = mm;
|
|
|
|
}
|
|
|
|
|
|
|
|
// And also get the offsets.
|
|
|
|
Vector offset0 = SS.GW.offset;
|
2008-04-19 11:44:44 +00:00
|
|
|
Vector offsetf = SS.GetEntity(e->assoc[0])->PointGetCoords();
|
2008-04-18 11:11:48 +00:00
|
|
|
|
|
|
|
// Animate transition, unless it's a tiny move.
|
|
|
|
SDWORD dt = (mp < 0.01) ? (-20) : (SDWORD)(100 + 1000*mp);
|
|
|
|
SDWORD tn, t0 = GetMilliseconds();
|
|
|
|
double s = 0;
|
|
|
|
do {
|
|
|
|
SS.GW.offset =
|
|
|
|
(offset0.ScaledBy(1 - s)).Plus(offsetf.ScaledBy(s));
|
|
|
|
Quaternion quat =
|
|
|
|
(quat0.ScaledBy(1 - s)).Plus(quatf.ScaledBy(s));
|
|
|
|
quat = quat.WithMagnitude(1);
|
|
|
|
SS.GW.projRight = quat.RotationU();
|
|
|
|
SS.GW.projUp = quat.RotationV();
|
|
|
|
PaintGraphics();
|
|
|
|
|
|
|
|
tn = GetMilliseconds();
|
|
|
|
s = (tn - t0)/((double)dt);
|
|
|
|
} while((tn - t0) < dt);
|
|
|
|
SS.GW.projRight = pr;
|
|
|
|
SS.GW.projUp = pu;
|
|
|
|
SS.GW.offset = offsetf;
|
|
|
|
|
|
|
|
SS.GW.hover.Clear();
|
2008-04-12 15:17:58 +00:00
|
|
|
SS.GW.ClearSelection();
|
|
|
|
InvalidateGraphics();
|
|
|
|
} else {
|
|
|
|
Error("Select plane or coordinate system before orienting.");
|
|
|
|
}
|
|
|
|
break;
|
2008-04-18 11:11:48 +00:00
|
|
|
}
|
2008-04-12 15:17:58 +00:00
|
|
|
|
|
|
|
default: oops();
|
|
|
|
}
|
|
|
|
InvalidateGraphics();
|
|
|
|
}
|
|
|
|
|
2008-04-18 07:06:37 +00:00
|
|
|
void GraphicsWindow::EnsureValidActives(void) {
|
|
|
|
bool change = false;
|
|
|
|
// The active group must exist, and not be the references.
|
2008-04-13 10:57:41 +00:00
|
|
|
Group *g = SS.group.FindByIdNoOops(activeGroup);
|
2008-04-18 07:06:37 +00:00
|
|
|
if((!g) || (g->h.v == Group::HGROUP_REFERENCES.v)) {
|
|
|
|
int i;
|
2008-04-18 11:11:48 +00:00
|
|
|
for(i = 0; i < SS.group.n; i++) {
|
2008-04-18 07:21:17 +00:00
|
|
|
if(SS.group.elem[i].h.v != Group::HGROUP_REFERENCES.v) {
|
2008-04-18 07:06:37 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2008-04-18 11:11:48 +00:00
|
|
|
if(i >= SS.group.n) oops();
|
2008-04-18 07:21:17 +00:00
|
|
|
activeGroup = SS.group.elem[i].h;
|
2008-04-18 07:06:37 +00:00
|
|
|
change = true;
|
2008-04-13 10:57:41 +00:00
|
|
|
}
|
|
|
|
|
2008-04-18 07:06:37 +00:00
|
|
|
// The active coordinate system must also exist.
|
|
|
|
if(activeCsys.v != Entity::NO_CSYS.v &&
|
|
|
|
!SS.entity.FindByIdNoOops(activeCsys))
|
|
|
|
{
|
|
|
|
activeCsys = Entity::NO_CSYS;
|
|
|
|
change = true;
|
2008-04-13 10:57:41 +00:00
|
|
|
}
|
2008-04-18 07:06:37 +00:00
|
|
|
if(change) SS.TW.Show();
|
2008-04-18 11:11:48 +00:00
|
|
|
|
|
|
|
EnableMenuById(MNU_NO_CSYS, (activeCsys.v != Entity::NO_CSYS.v));
|
2008-04-13 10:57:41 +00:00
|
|
|
}
|
|
|
|
|
2008-04-14 10:28:32 +00:00
|
|
|
void GraphicsWindow::MenuEdit(int id) {
|
2008-04-12 15:17:58 +00:00
|
|
|
switch(id) {
|
|
|
|
case MNU_UNSELECT_ALL:
|
|
|
|
SS.GW.ClearSelection();
|
2008-04-13 10:57:41 +00:00
|
|
|
SS.GW.pendingOperation = 0;
|
|
|
|
SS.GW.pendingDescription = NULL;
|
|
|
|
SS.TW.Show();
|
|
|
|
break;
|
|
|
|
|
2008-04-14 10:28:32 +00:00
|
|
|
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;
|
2008-04-19 11:09:47 +00:00
|
|
|
if(s->entity.v) {
|
|
|
|
r = s->entity.request();
|
2008-04-14 10:28:32 +00:00
|
|
|
}
|
|
|
|
if(r.v) SS.request.Tag(r, 1);
|
|
|
|
}
|
|
|
|
SS.request.RemoveTagged();
|
|
|
|
|
|
|
|
SS.GenerateAll();
|
|
|
|
SS.GW.ClearSelection();
|
|
|
|
SS.GW.hover.Clear();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-04-13 10:57:41 +00:00
|
|
|
default: oops();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-14 10:28:32 +00:00
|
|
|
void GraphicsWindow::MenuRequest(int id) {
|
2008-04-13 10:57:41 +00:00
|
|
|
char *s;
|
|
|
|
switch(id) {
|
2008-04-18 07:06:37 +00:00
|
|
|
case MNU_SEL_CSYS:
|
|
|
|
SS.GW.GroupSelection();
|
|
|
|
if(SS.GW.gs.n == 1 && SS.GW.gs.csyss == 1) {
|
|
|
|
SS.GW.activeCsys = SS.GW.gs.entity[0];
|
|
|
|
SS.GW.ClearSelection();
|
|
|
|
} else {
|
|
|
|
Error("Select 2d coordinate system (e.g., the XY plane) "
|
|
|
|
"before locking on.");
|
|
|
|
}
|
|
|
|
SS.GW.EnsureValidActives();
|
|
|
|
SS.TW.Show();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MNU_NO_CSYS:
|
|
|
|
SS.GW.activeCsys = Entity::NO_CSYS;
|
|
|
|
SS.GW.EnsureValidActives();
|
|
|
|
SS.TW.Show();
|
|
|
|
break;
|
|
|
|
|
2008-04-13 10:57:41 +00:00
|
|
|
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;
|
|
|
|
c:
|
|
|
|
SS.GW.pendingOperation = id;
|
|
|
|
SS.GW.pendingDescription = s;
|
|
|
|
SS.TW.Show();
|
2008-04-12 15:17:58 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default: oops();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-19 11:09:47 +00:00
|
|
|
void GraphicsWindow::UpdateDraggedEntity(hEntity hp, double mx, double my) {
|
|
|
|
Entity *p = SS.GetEntity(hp);
|
2008-04-19 11:44:44 +00:00
|
|
|
Vector pos = p->PointGetCoords();
|
2008-04-14 10:28:32 +00:00
|
|
|
UpdateDraggedPoint(&pos, mx, my);
|
2008-04-19 11:44:44 +00:00
|
|
|
p->PointForceTo(pos);
|
2008-04-14 10:28:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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));
|
2008-04-13 10:57:41 +00:00
|
|
|
|
|
|
|
orig.mouse.x = mx;
|
|
|
|
orig.mouse.y = my;
|
|
|
|
InvalidateGraphics();
|
|
|
|
}
|
|
|
|
|
2008-03-27 09:53:51 +00:00
|
|
|
void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
|
|
|
bool middleDown, bool rightDown, bool shiftDown, bool ctrlDown)
|
|
|
|
{
|
2008-04-12 14:12:26 +00:00
|
|
|
Point2d mp = { x, y };
|
|
|
|
|
2008-03-27 09:53:51 +00:00
|
|
|
if(middleDown) {
|
2008-04-12 14:12:26 +00:00
|
|
|
hover.Clear();
|
|
|
|
|
2008-03-27 09:53:51 +00:00
|
|
|
double dx = (x - orig.mouse.x) / scale;
|
|
|
|
double dy = (y - orig.mouse.y) / scale;
|
|
|
|
|
2008-04-14 10:28:32 +00:00
|
|
|
// When the view is locked, permit only translation (pan).
|
|
|
|
if(shiftDown || viewLocked) {
|
2008-04-12 15:17:58 +00:00
|
|
|
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;
|
2008-04-14 10:28:32 +00:00
|
|
|
} else if(ctrlDown && !viewLocked) {
|
2008-03-27 09:53:51 +00:00
|
|
|
double theta = atan2(orig.mouse.y, orig.mouse.x);
|
|
|
|
theta -= atan2(y, x);
|
|
|
|
|
2008-04-12 15:17:58 +00:00
|
|
|
Vector normal = orig.projRight.Cross(orig.projUp);
|
2008-03-27 09:53:51 +00:00
|
|
|
projRight = orig.projRight.RotatedAbout(normal, theta);
|
2008-04-12 15:17:58 +00:00
|
|
|
projUp = orig.projUp.RotatedAbout(normal, theta);
|
2008-03-27 09:53:51 +00:00
|
|
|
|
|
|
|
NormalizeProjectionVectors();
|
2008-04-14 10:28:32 +00:00
|
|
|
} else if(!viewLocked) {
|
2008-03-27 09:53:51 +00:00
|
|
|
double s = 0.3*(PI/180); // degrees per pixel
|
2008-04-12 15:17:58 +00:00
|
|
|
projRight = orig.projRight.RotatedAbout(orig.projUp, -s*dx);
|
|
|
|
projUp = orig.projUp.RotatedAbout(orig.projRight, s*dy);
|
2008-03-27 09:53:51 +00:00
|
|
|
|
|
|
|
NormalizeProjectionVectors();
|
|
|
|
}
|
|
|
|
|
2008-04-11 11:13:47 +00:00
|
|
|
orig.projRight = projRight;
|
2008-04-12 15:17:58 +00:00
|
|
|
orig.projUp = projUp;
|
2008-04-11 11:13:47 +00:00
|
|
|
orig.offset = offset;
|
|
|
|
orig.mouse.x = x;
|
|
|
|
orig.mouse.y = y;
|
|
|
|
|
2008-04-11 12:47:14 +00:00
|
|
|
InvalidateGraphics();
|
2008-04-13 10:57:41 +00:00
|
|
|
} else if(leftDown) {
|
2008-04-14 10:28:32 +00:00
|
|
|
// We are left-dragging. This is often used to drag points, or
|
|
|
|
// constraint labels.
|
2008-04-19 11:09:47 +00:00
|
|
|
if(hover.entity.v &&
|
|
|
|
SS.GetEntity(hover.entity)->IsPoint() &&
|
2008-04-19 11:44:44 +00:00
|
|
|
!SS.GetEntity(hover.entity)->PointIsFromReferences())
|
2008-04-19 11:09:47 +00:00
|
|
|
{
|
2008-04-13 10:57:41 +00:00
|
|
|
ClearSelection();
|
2008-04-19 11:09:47 +00:00
|
|
|
UpdateDraggedEntity(hover.entity, x, y);
|
2008-04-14 10:28:32 +00:00
|
|
|
} else if(hover.constraint.v &&
|
|
|
|
SS.GetConstraint(hover.constraint)->HasLabel())
|
|
|
|
{
|
|
|
|
ClearSelection();
|
|
|
|
Constraint *c = SS.constraint.FindById(hover.constraint);
|
|
|
|
UpdateDraggedPoint(&(c->disp.offset), x, y);
|
2008-04-13 10:57:41 +00:00
|
|
|
}
|
2008-04-12 14:12:26 +00:00
|
|
|
} else {
|
2008-04-13 10:57:41 +00:00
|
|
|
if(pendingOperation == PENDING_OPERATION_DRAGGING_POINT) {
|
2008-04-19 11:09:47 +00:00
|
|
|
UpdateDraggedEntity(pendingPoint, x, y);
|
2008-04-13 10:57:41 +00:00
|
|
|
} else {
|
|
|
|
// Do our usual hit testing, for the selection.
|
|
|
|
Selection s;
|
|
|
|
HitTestMakeSelection(mp, &s);
|
|
|
|
if(!s.Equals(&hover)) {
|
|
|
|
hover = s;
|
|
|
|
InvalidateGraphics();
|
|
|
|
}
|
2008-04-12 14:12:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GraphicsWindow::Selection::Equals(Selection *b) {
|
2008-04-14 10:28:32 +00:00
|
|
|
if(entity.v != b->entity.v) return false;
|
|
|
|
if(constraint.v != b->constraint.v) return false;
|
2008-04-12 14:12:26 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool GraphicsWindow::Selection::IsEmpty(void) {
|
2008-04-14 10:28:32 +00:00
|
|
|
if(entity.v) return false;
|
|
|
|
if(constraint.v) return false;
|
2008-04-12 14:12:26 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
void GraphicsWindow::Selection::Clear(void) {
|
2008-04-19 11:09:47 +00:00
|
|
|
entity.v = constraint.v = 0;
|
2008-04-12 14:12:26 +00:00
|
|
|
}
|
|
|
|
void GraphicsWindow::Selection::Draw(void) {
|
2008-04-19 11:09:47 +00:00
|
|
|
if(entity.v) SS.GetEntity (entity )->Draw();
|
|
|
|
if(constraint.v) SS.GetConstraint(constraint)->Draw();
|
2008-04-12 14:12:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GraphicsWindow::HitTestMakeSelection(Point2d mp, Selection *dest) {
|
|
|
|
int i;
|
|
|
|
double d, dmin = 1e12;
|
|
|
|
|
2008-04-14 10:28:32 +00:00
|
|
|
memset(dest, 0, sizeof(*dest));
|
2008-04-12 14:12:26 +00:00
|
|
|
|
2008-04-19 11:09:47 +00:00
|
|
|
// Do the entities
|
2008-04-18 11:11:48 +00:00
|
|
|
for(i = 0; i < SS.entity.n; i++) {
|
2008-04-18 07:21:17 +00:00
|
|
|
d = SS.entity.elem[i].GetDistance(mp);
|
2008-04-12 14:12:26 +00:00
|
|
|
if(d < 10 && d < dmin) {
|
2008-04-14 10:28:32 +00:00
|
|
|
memset(dest, 0, sizeof(*dest));
|
2008-04-18 07:21:17 +00:00
|
|
|
dest->entity = SS.entity.elem[i].h;
|
2008-04-19 11:09:47 +00:00
|
|
|
dmin = d;
|
2008-04-12 14:12:26 +00:00
|
|
|
}
|
2008-03-27 09:53:51 +00:00
|
|
|
}
|
2008-04-14 10:28:32 +00:00
|
|
|
|
|
|
|
// Constraints
|
2008-04-18 11:11:48 +00:00
|
|
|
for(i = 0; i < SS.constraint.n; i++) {
|
2008-04-18 07:21:17 +00:00
|
|
|
d = SS.constraint.elem[i].GetDistance(mp);
|
2008-04-14 10:28:32 +00:00
|
|
|
if(d < 10 && d < dmin) {
|
|
|
|
memset(dest, 0, sizeof(*dest));
|
2008-04-18 07:21:17 +00:00
|
|
|
dest->constraint = SS.constraint.elem[i].h;
|
2008-04-19 11:09:47 +00:00
|
|
|
dmin = d;
|
2008-04-14 10:28:32 +00:00
|
|
|
}
|
|
|
|
}
|
2008-03-27 09:53:51 +00:00
|
|
|
}
|
|
|
|
|
2008-04-12 15:17:58 +00:00
|
|
|
void GraphicsWindow::ClearSelection(void) {
|
|
|
|
for(int i = 0; i < MAX_SELECTED; i++) {
|
|
|
|
selection[i].Clear();
|
|
|
|
}
|
|
|
|
InvalidateGraphics();
|
|
|
|
}
|
|
|
|
|
|
|
|
void GraphicsWindow::GroupSelection(void) {
|
|
|
|
gs.points = gs.entities = 0;
|
2008-04-14 10:28:32 +00:00
|
|
|
gs.csyss = gs.lineSegments = 0;
|
2008-04-12 15:17:58 +00:00
|
|
|
gs.n = 0;
|
|
|
|
int i;
|
|
|
|
for(i = 0; i < MAX_SELECTED; i++) {
|
|
|
|
Selection *s = &(selection[i]);
|
|
|
|
if(s->entity.v) {
|
|
|
|
gs.entity[(gs.entities)++] = s->entity;
|
|
|
|
(gs.n)++;
|
|
|
|
|
|
|
|
Entity *e = SS.entity.FindById(s->entity);
|
2008-04-14 10:28:32 +00:00
|
|
|
switch(e->type) {
|
|
|
|
case Entity::CSYS_2D: (gs.csyss)++; break;
|
|
|
|
case Entity::LINE_SEGMENT: (gs.lineSegments)++; break;
|
2008-04-12 15:17:58 +00:00
|
|
|
}
|
2008-04-19 11:09:47 +00:00
|
|
|
if(e->IsPoint()) {
|
|
|
|
gs.point[(gs.points)++] = s->entity;
|
|
|
|
}
|
2008-04-12 15:17:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-27 09:53:51 +00:00
|
|
|
void GraphicsWindow::MouseMiddleDown(double x, double y) {
|
|
|
|
orig.offset = offset;
|
2008-04-12 15:17:58 +00:00
|
|
|
orig.projUp = projUp;
|
2008-03-27 09:53:51 +00:00
|
|
|
orig.projRight = projRight;
|
|
|
|
orig.mouse.x = x;
|
|
|
|
orig.mouse.y = y;
|
|
|
|
}
|
|
|
|
|
2008-04-13 10:57:41 +00:00
|
|
|
hRequest GraphicsWindow::AddRequest(int type) {
|
|
|
|
Request r;
|
|
|
|
memset(&r, 0, sizeof(r));
|
|
|
|
r.group = activeGroup;
|
2008-04-18 07:06:37 +00:00
|
|
|
r.csys = activeCsys;
|
2008-04-13 10:57:41 +00:00
|
|
|
r.type = type;
|
|
|
|
SS.request.AddAndAssignId(&r);
|
|
|
|
SS.GenerateAll();
|
|
|
|
return r.h;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
2008-04-12 14:12:26 +00:00
|
|
|
// Make sure the hover is up to date.
|
2008-04-13 10:57:41 +00:00
|
|
|
MouseMoved(mx, my, false, false, false, false, false);
|
|
|
|
orig.mouse.x = mx;
|
|
|
|
orig.mouse.y = my;
|
|
|
|
|
|
|
|
// The current mouse location
|
|
|
|
Vector v = offset.ScaledBy(-1);
|
|
|
|
v = v.Plus(projRight.ScaledBy(mx/scale));
|
|
|
|
v = v.Plus(projUp.ScaledBy(my/scale));
|
|
|
|
|
|
|
|
hRequest hr;
|
|
|
|
switch(pendingOperation) {
|
|
|
|
case MNU_DATUM_POINT:
|
|
|
|
hr = AddRequest(Request::DATUM_POINT);
|
2008-04-19 11:44:44 +00:00
|
|
|
SS.GetEntity(hr.entity(0))->PointForceTo(v);
|
2008-04-13 10:57:41 +00:00
|
|
|
pendingOperation = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MNU_LINE_SEGMENT:
|
|
|
|
hr = AddRequest(Request::LINE_SEGMENT);
|
2008-04-19 11:44:44 +00:00
|
|
|
SS.GetEntity(hr.entity(1))->PointForceTo(v);
|
2008-04-13 10:57:41 +00:00
|
|
|
pendingOperation = PENDING_OPERATION_DRAGGING_POINT;
|
2008-04-19 11:09:47 +00:00
|
|
|
pendingPoint = hr.entity(2);
|
2008-04-13 14:28:35 +00:00
|
|
|
pendingDescription = "click to place next point of line";
|
2008-04-19 11:44:44 +00:00
|
|
|
SS.GetEntity(pendingPoint)->PointForceTo(v);
|
2008-04-13 10:57:41 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case PENDING_OPERATION_DRAGGING_POINT:
|
2008-04-19 11:09:47 +00:00
|
|
|
// The MouseMoved event has already dragged it under the cursor.
|
2008-04-13 10:57:41 +00:00
|
|
|
pendingOperation = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0:
|
|
|
|
default: {
|
|
|
|
pendingOperation = 0;
|
|
|
|
|
|
|
|
if(hover.IsEmpty()) break;
|
|
|
|
|
|
|
|
// If an item is hovered, then by clicking on it, we toggle its
|
|
|
|
// selection state.
|
|
|
|
int i;
|
|
|
|
for(i = 0; i < MAX_SELECTED; i++) {
|
|
|
|
if(selection[i].Equals(&hover)) {
|
|
|
|
selection[i].Clear();
|
|
|
|
break;
|
|
|
|
}
|
2008-04-12 14:12:26 +00:00
|
|
|
}
|
2008-04-13 10:57:41 +00:00
|
|
|
if(i != MAX_SELECTED) break;
|
|
|
|
|
|
|
|
for(i = 0; i < MAX_SELECTED; i++) {
|
|
|
|
if(selection[i].IsEmpty()) {
|
|
|
|
selection[i] = hover;
|
|
|
|
break;
|
|
|
|
}
|
2008-04-12 14:12:26 +00:00
|
|
|
}
|
2008-04-13 10:57:41 +00:00
|
|
|
break;
|
2008-04-12 14:12:26 +00:00
|
|
|
}
|
|
|
|
}
|
2008-04-13 10:57:41 +00:00
|
|
|
|
|
|
|
SS.TW.Show();
|
|
|
|
InvalidateGraphics();
|
2008-03-27 09:53:51 +00:00
|
|
|
}
|
|
|
|
|
2008-04-01 10:48:44 +00:00
|
|
|
void GraphicsWindow::MouseScroll(double x, double y, int delta) {
|
|
|
|
double offsetRight = offset.Dot(projRight);
|
2008-04-12 15:17:58 +00:00
|
|
|
double offsetUp = offset.Dot(projUp);
|
2008-04-01 10:48:44 +00:00
|
|
|
|
|
|
|
double righti = x/scale - offsetRight;
|
2008-04-12 15:17:58 +00:00
|
|
|
double upi = y/scale - offsetUp;
|
2008-04-01 10:48:44 +00:00
|
|
|
|
|
|
|
if(delta > 0) {
|
2008-04-12 15:17:58 +00:00
|
|
|
scale *= 1.2;
|
2008-04-01 10:48:44 +00:00
|
|
|
} else {
|
2008-04-12 15:17:58 +00:00
|
|
|
scale /= 1.2;
|
2008-04-01 10:48:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
double rightf = x/scale - offsetRight;
|
2008-04-12 15:17:58 +00:00
|
|
|
double upf = y/scale - offsetUp;
|
2008-04-01 10:48:44 +00:00
|
|
|
|
|
|
|
offset = offset.Plus(projRight.ScaledBy(rightf - righti));
|
2008-04-12 15:17:58 +00:00
|
|
|
offset = offset.Plus(projUp.ScaledBy(upf - upi));
|
2008-04-01 10:48:44 +00:00
|
|
|
|
2008-04-11 12:47:14 +00:00
|
|
|
InvalidateGraphics();
|
|
|
|
}
|
|
|
|
|
|
|
|
void GraphicsWindow::ToggleBool(int link, DWORD v) {
|
|
|
|
bool *vb = (bool *)v;
|
|
|
|
*vb = !*vb;
|
|
|
|
|
2008-04-13 10:57:41 +00:00
|
|
|
SS.GenerateAll();
|
2008-04-11 12:47:14 +00:00
|
|
|
InvalidateGraphics();
|
|
|
|
SS.TW.Show();
|
|
|
|
}
|
|
|
|
|
|
|
|
void GraphicsWindow::ToggleAnyDatumShown(int link, DWORD v) {
|
|
|
|
bool t = !(SS.GW.show2dCsyss && SS.GW.showAxes && SS.GW.showPoints);
|
|
|
|
SS.GW.show2dCsyss = t;
|
|
|
|
SS.GW.showAxes = t;
|
|
|
|
SS.GW.showPoints = t;
|
|
|
|
|
2008-04-13 10:57:41 +00:00
|
|
|
SS.GenerateAll();
|
2008-04-11 12:47:14 +00:00
|
|
|
InvalidateGraphics();
|
|
|
|
SS.TW.Show();
|
2008-04-01 10:48:44 +00:00
|
|
|
}
|
|
|
|
|
2008-03-27 09:53:51 +00:00
|
|
|
void GraphicsWindow::Paint(int w, int h) {
|
2008-04-01 10:48:44 +00:00
|
|
|
width = w; height = h;
|
|
|
|
|
2008-03-27 09:53:51 +00:00
|
|
|
glViewport(0, 0, w, h);
|
|
|
|
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
|
|
|
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
|
|
|
|
glScaled(scale*2.0/w, scale*2.0/h, 0);
|
|
|
|
|
|
|
|
double tx = projRight.Dot(offset);
|
2008-04-12 15:17:58 +00:00
|
|
|
double ty = projUp.Dot(offset);
|
2008-03-27 09:53:51 +00:00
|
|
|
double mat[16];
|
|
|
|
MakeMatrix(mat, projRight.x, projRight.y, projRight.z, tx,
|
2008-04-12 15:17:58 +00:00
|
|
|
projUp.x, projUp.y, projUp.z, ty,
|
2008-03-27 09:53:51 +00:00
|
|
|
0, 0, 0, 0,
|
|
|
|
0, 0, 0, 1);
|
|
|
|
glMultMatrixd(mat);
|
|
|
|
|
2008-04-11 11:13:47 +00:00
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
glEnable(GL_LINE_SMOOTH);
|
2008-03-27 09:53:51 +00:00
|
|
|
glEnable(GL_DEPTH_TEST);
|
2008-04-11 11:13:47 +00:00
|
|
|
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
|
2008-03-27 09:53:51 +00:00
|
|
|
|
|
|
|
glClearIndex((GLfloat)0);
|
|
|
|
glClearDepth(1.0);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
|
2008-04-11 12:47:14 +00:00
|
|
|
|
2008-04-09 08:39:01 +00:00
|
|
|
int i;
|
2008-04-12 14:12:26 +00:00
|
|
|
|
|
|
|
// First, draw the entire scene.
|
2008-04-19 11:09:47 +00:00
|
|
|
glxUnlockColor();
|
2008-04-18 11:11:48 +00:00
|
|
|
for(i = 0; i < SS.entity.n; i++) {
|
2008-04-18 07:21:17 +00:00
|
|
|
SS.entity.elem[i].Draw();
|
2008-04-09 08:39:01 +00:00
|
|
|
}
|
2008-04-18 11:11:48 +00:00
|
|
|
for(i = 0; i < SS.constraint.n; i++) {
|
2008-04-18 07:21:17 +00:00
|
|
|
SS.constraint.elem[i].Draw();
|
2008-04-14 10:28:32 +00:00
|
|
|
}
|
2008-04-12 14:12:26 +00:00
|
|
|
|
|
|
|
// Then redraw whatever the mouse is hovering over, highlighted. Have
|
|
|
|
// to disable the depth test, so that we can overdraw.
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
2008-04-19 11:09:47 +00:00
|
|
|
glxLockColorTo(1, 1, 0);
|
2008-04-12 14:12:26 +00:00
|
|
|
hover.Draw();
|
|
|
|
|
|
|
|
// And finally draw the selection, same mechanism.
|
2008-04-19 11:09:47 +00:00
|
|
|
glxLockColorTo(1, 0, 0);
|
2008-04-12 14:12:26 +00:00
|
|
|
for(i = 0; i < MAX_SELECTED; i++) {
|
|
|
|
selection[i].Draw();
|
|
|
|
}
|
2008-03-27 09:53:51 +00:00
|
|
|
}
|
|
|
|
|