Merge branch 'master' into python
13
CHANGELOG.md
|
@ -29,6 +29,8 @@ New sketch features:
|
|||
* Property browser now shows amount of degrees of freedom in group list.
|
||||
It also shows a yellow "err" if the sketch has problems (e.g. self
|
||||
intersecting) that would propagate in subsequent groups.
|
||||
* It is now possible to press "g" to toggle construction on new objects while
|
||||
they are still being drawn.
|
||||
|
||||
New constraint features:
|
||||
* When dragging an arc or rectangle point, it will be automatically
|
||||
|
@ -47,6 +49,10 @@ New constraint features:
|
|||
would have been redundant with other ones.
|
||||
* New option to open the constraint editor for newly created constraints
|
||||
with a value.
|
||||
* New "redundant constraint timeout (in ms)" option to prevent UI freeze
|
||||
when looking for redundant constraints.
|
||||
* Swap vertical and horizontal constraints when pasting rotated by 90/270
|
||||
degrees.
|
||||
|
||||
New export/import features:
|
||||
* Link IDF circuit boards in an assembly (.emn files)
|
||||
|
@ -63,12 +69,17 @@ New export/import features:
|
|||
* VRML (WRL) triangle meshes can now be exported, useful for e.g. [KiCAD](http://kicad.org).
|
||||
* Export 2d section: custom styled entities that lie in the same
|
||||
plane as the exported section are included.
|
||||
* Added ExportBackgroundColor in configuration for EPS, PDF, and SVG files.
|
||||
* STEP export includes object colors and transparency.
|
||||
|
||||
New rendering features:
|
||||
* The "Show/hide hidden lines" button is now a tri-state button that allows
|
||||
showing all lines (on top of shaded mesh), stippling occluded lines
|
||||
or not drawing them at all.
|
||||
* The "Show/hide outlines" button is now independent from "Show/hide edges".
|
||||
* "View | Darken Inactive Solids" added. When turned off and a "sketch in plane"
|
||||
group is active solids form previous groups will not be "darkened" (have the
|
||||
s000d-#def-dim-solid style applied to them).
|
||||
|
||||
New measurement/analysis features:
|
||||
* New choice for base unit, meters.
|
||||
|
@ -85,7 +96,6 @@ New measurement/analysis features:
|
|||
workplane is displayed.
|
||||
|
||||
Other new features:
|
||||
* Added ExportBackgroundColor in configuration for EPS, PDF, and SVG files.
|
||||
* Improvements to the text window for selected entities and constraints.
|
||||
* Ambient light source added in text window to allow flat shaded renderings.
|
||||
* New command-line interface, for batch exporting and more.
|
||||
|
@ -114,6 +124,7 @@ Other new features:
|
|||
* New cmake build options using -DENABLE_OPENMP=yes and -DENABLE_LTO=yes
|
||||
to enable support for multi-threading and link-time optimization.
|
||||
* "Shift+Scroll" for ten times finer zoom.
|
||||
* Chinese translation
|
||||
|
||||
Bugs fixed:
|
||||
* Fixed broken --view options for command line thumbnail image creation.
|
||||
|
|
|
@ -17,8 +17,8 @@ so any savefiles should first be archived.
|
|||
Licensing
|
||||
---------------
|
||||
|
||||
SolveSpace is licensed under the GPLv3 and any contributions must be made available
|
||||
under the terms of that license.
|
||||
SolveSpace is licensed under the GPLv3 or later and any contributions
|
||||
must be made available under the terms of that license.
|
||||
|
||||
Contributing translations
|
||||
-------------------------
|
||||
|
|
|
@ -259,4 +259,4 @@ and debug SolveSpace.
|
|||
License
|
||||
-------
|
||||
|
||||
SolveSpace is distributed under the terms of the [GPL v3 license](COPYING.txt).
|
||||
SolveSpace is distributed under the terms of the [GPL v3](COPYING.txt) or later.
|
||||
|
|
Before Width: | Height: | Size: 819 B After Width: | Height: | Size: 258 B |
Before Width: | Height: | Size: 686 B After Width: | Height: | Size: 218 B |
Before Width: | Height: | Size: 454 B After Width: | Height: | Size: 214 B |
Before Width: | Height: | Size: 710 B After Width: | Height: | Size: 202 B |
Before Width: | Height: | Size: 801 B After Width: | Height: | Size: 190 B |
Before Width: | Height: | Size: 739 B After Width: | Height: | Size: 203 B |
Before Width: | Height: | Size: 920 B After Width: | Height: | Size: 249 B |
Before Width: | Height: | Size: 620 B After Width: | Height: | Size: 207 B |
Before Width: | Height: | Size: 664 B After Width: | Height: | Size: 243 B |
Before Width: | Height: | Size: 418 B After Width: | Height: | Size: 161 B |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 227 B |
Before Width: | Height: | Size: 512 B After Width: | Height: | Size: 229 B |
Before Width: | Height: | Size: 401 B After Width: | Height: | Size: 245 B |
Before Width: | Height: | Size: 480 B After Width: | Height: | Size: 223 B |
Before Width: | Height: | Size: 511 B After Width: | Height: | Size: 153 B |
Before Width: | Height: | Size: 412 B After Width: | Height: | Size: 160 B |
Before Width: | Height: | Size: 916 B After Width: | Height: | Size: 235 B |
Before Width: | Height: | Size: 531 B After Width: | Height: | Size: 165 B |
Before Width: | Height: | Size: 427 B After Width: | Height: | Size: 214 B |
Before Width: | Height: | Size: 394 B After Width: | Height: | Size: 132 B |
Before Width: | Height: | Size: 596 B After Width: | Height: | Size: 267 B |
Before Width: | Height: | Size: 418 B After Width: | Height: | Size: 159 B |
Before Width: | Height: | Size: 413 B After Width: | Height: | Size: 178 B |
Before Width: | Height: | Size: 680 B After Width: | Height: | Size: 226 B |
Before Width: | Height: | Size: 673 B After Width: | Height: | Size: 202 B |
Before Width: | Height: | Size: 597 B After Width: | Height: | Size: 196 B |
Before Width: | Height: | Size: 507 B After Width: | Height: | Size: 214 B |
Before Width: | Height: | Size: 871 B After Width: | Height: | Size: 207 B |
Before Width: | Height: | Size: 411 B After Width: | Height: | Size: 171 B |
Before Width: | Height: | Size: 515 B After Width: | Height: | Size: 149 B |
Before Width: | Height: | Size: 666 B After Width: | Height: | Size: 232 B |
Before Width: | Height: | Size: 784 B After Width: | Height: | Size: 217 B |
Before Width: | Height: | Size: 575 B After Width: | Height: | Size: 224 B |
Before Width: | Height: | Size: 515 B After Width: | Height: | Size: 177 B |
Before Width: | Height: | Size: 557 B After Width: | Height: | Size: 199 B |
Before Width: | Height: | Size: 739 B After Width: | Height: | Size: 203 B |
Before Width: | Height: | Size: 703 B After Width: | Height: | Size: 285 B |
Before Width: | Height: | Size: 683 B After Width: | Height: | Size: 352 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 335 B |
Before Width: | Height: | Size: 639 B After Width: | Height: | Size: 177 B |
Before Width: | Height: | Size: 345 B After Width: | Height: | Size: 196 B |
Before Width: | Height: | Size: 539 B After Width: | Height: | Size: 218 B |
Before Width: | Height: | Size: 365 B After Width: | Height: | Size: 208 B |
Before Width: | Height: | Size: 733 B After Width: | Height: | Size: 289 B |
Before Width: | Height: | Size: 394 B After Width: | Height: | Size: 132 B |
Before Width: | Height: | Size: 462 B After Width: | Height: | Size: 193 B |
|
@ -127,7 +127,7 @@ hConstraint Constraint::ConstrainCoincident(hEntity ptA, hEntity ptB) {
|
|||
Entity::NO_ENTITY, Entity::NO_ENTITY, /*other=*/false, /*other2=*/false);
|
||||
}
|
||||
|
||||
void Constraint::ConstrainArcLineTangent(Constraint *c, Entity *line, Entity *arc) {
|
||||
bool Constraint::ConstrainArcLineTangent(Constraint *c, Entity *line, Entity *arc) {
|
||||
Vector l0 = SK.GetEntity(line->point[0])->PointGetNum(),
|
||||
l1 = SK.GetEntity(line->point[1])->PointGetNum();
|
||||
Vector a1 = SK.GetEntity(arc->point[1])->PointGetNum(),
|
||||
|
@ -140,11 +140,12 @@ void Constraint::ConstrainArcLineTangent(Constraint *c, Entity *line, Entity *ar
|
|||
Error(_("The tangent arc and line segment must share an "
|
||||
"endpoint. Constrain them with Constrain -> "
|
||||
"On Point before constraining tangent."));
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Constraint::ConstrainCubicLineTangent(Constraint *c, Entity *line, Entity *cubic) {
|
||||
bool Constraint::ConstrainCubicLineTangent(Constraint *c, Entity *line, Entity *cubic) {
|
||||
Vector l0 = SK.GetEntity(line->point[0])->PointGetNum(),
|
||||
l1 = SK.GetEntity(line->point[1])->PointGetNum();
|
||||
Vector as = cubic->CubicGetStartNum(),
|
||||
|
@ -158,11 +159,12 @@ void Constraint::ConstrainCubicLineTangent(Constraint *c, Entity *line, Entity *
|
|||
Error(_("The tangent cubic and line segment must share an "
|
||||
"endpoint. Constrain them with Constrain -> "
|
||||
"On Point before constraining tangent."));
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Constraint::ConstrainCurveCurveTangent(Constraint *c, Entity *eA, Entity *eB) {
|
||||
bool Constraint::ConstrainCurveCurveTangent(Constraint *c, Entity *eA, Entity *eB) {
|
||||
Vector as = eA->EndpointStart(),
|
||||
af = eA->EndpointFinish(),
|
||||
bs = eB->EndpointStart(),
|
||||
|
@ -183,8 +185,9 @@ void Constraint::ConstrainCurveCurveTangent(Constraint *c, Entity *eA, Entity *e
|
|||
Error(_("The curves must share an endpoint. Constrain them "
|
||||
"with Constrain -> On Point before constraining "
|
||||
"tangent."));
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Constraint::MenuConstrain(Command id) {
|
||||
|
@ -417,8 +420,11 @@ void Constraint::MenuConstrain(Command id) {
|
|||
c.ptA = gs.point[0];
|
||||
|
||||
// If a point is at-midpoint, then no reason to also constrain
|
||||
// it on-line; so auto-remove that.
|
||||
// it on-line; so auto-remove that. Handle as one undo group.
|
||||
SS.UndoRemember();
|
||||
DeleteAllConstraintsFor(Type::PT_ON_LINE, c.entityA, c.ptA);
|
||||
AddConstraint(&c, /*rememberForUndo=*/false);
|
||||
break;
|
||||
} else if(gs.lineSegments == 1 && gs.workplanes == 1 && gs.n == 2) {
|
||||
c.type = Type::AT_MIDPOINT;
|
||||
int i = SK.GetEntity(gs.entity[0])->IsWorkplane() ? 1 : 0;
|
||||
|
@ -493,6 +499,7 @@ void Constraint::MenuConstrain(Command id) {
|
|||
"(symmetric about workplane)\n"));
|
||||
return;
|
||||
}
|
||||
// We may remove constraints so remember manually
|
||||
if(c.entityA == Entity::NO_ENTITY) {
|
||||
// Horizontal / vertical symmetry, implicit symmetry plane
|
||||
// normal to the workplane
|
||||
|
@ -514,10 +521,14 @@ void Constraint::MenuConstrain(Command id) {
|
|||
if(gs.lineSegments == 1) {
|
||||
// If this line segment is already constrained horiz or
|
||||
// vert, then auto-remove that redundant constraint.
|
||||
// Handle as one undo group.
|
||||
SS.UndoRemember();
|
||||
DeleteAllConstraintsFor(Type::HORIZONTAL, (gs.entity[0]),
|
||||
Entity::NO_ENTITY);
|
||||
DeleteAllConstraintsFor(Type::VERTICAL, (gs.entity[0]),
|
||||
Entity::NO_ENTITY);
|
||||
AddConstraint(&c, /*rememberForUndo=*/false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
AddConstraint(&c);
|
||||
|
@ -682,7 +693,9 @@ void Constraint::MenuConstrain(Command id) {
|
|||
if(line->type == Entity::Type::ARC_OF_CIRCLE) {
|
||||
swap(line, arc);
|
||||
}
|
||||
ConstrainArcLineTangent(&c, line, arc);
|
||||
if(!ConstrainArcLineTangent(&c, line, arc)) {
|
||||
return;
|
||||
}
|
||||
c.type = Type::ARC_LINE_TANGENT;
|
||||
c.entityA = arc->h;
|
||||
c.entityB = line->h;
|
||||
|
@ -692,7 +705,9 @@ void Constraint::MenuConstrain(Command id) {
|
|||
if(line->type == Entity::Type::CUBIC) {
|
||||
swap(line, cubic);
|
||||
}
|
||||
ConstrainCubicLineTangent(&c, line, cubic);
|
||||
if(!ConstrainCubicLineTangent(&c, line, cubic)) {
|
||||
return;
|
||||
}
|
||||
c.type = Type::CUBIC_LINE_TANGENT;
|
||||
c.entityA = cubic->h;
|
||||
c.entityB = line->h;
|
||||
|
@ -703,7 +718,9 @@ void Constraint::MenuConstrain(Command id) {
|
|||
}
|
||||
Entity *eA = SK.GetEntity(gs.entity[0]),
|
||||
*eB = SK.GetEntity(gs.entity[1]);
|
||||
ConstrainCurveCurveTangent(&c, eA, eB);
|
||||
if(!ConstrainCurveCurveTangent(&c, eA, eB)) {
|
||||
return;
|
||||
}
|
||||
c.type = Type::CURVE_CURVE_TANGENT;
|
||||
c.entityA = eA->h;
|
||||
c.entityB = eB->h;
|
||||
|
|
|
@ -318,8 +318,9 @@ void TextWindow::DescribeSelection() {
|
|||
Printf(true, " at " PT_AS_STR, COSTR(p0));
|
||||
Vector p1 = SK.GetEntity(gs.point[1])->PointGetNum();
|
||||
Printf(false, " " PT_AS_STR, COSTR(p1));
|
||||
double d = (p1.Minus(p0)).Magnitude();
|
||||
Printf(true, " d = %Fi%s", SS.MmToString(d).c_str());
|
||||
Vector dv = p1.Minus(p0);
|
||||
Printf(true, " d = %Fi%s", SS.MmToString(dv.Magnitude()).c_str());
|
||||
Printf(false, " d(x, y, z) = " PT_AS_STR, COSTR(dv));
|
||||
} else if(gs.n == 2 && gs.points == 1 && gs.circlesOrArcs == 1) {
|
||||
Entity *ec = SK.GetEntity(gs.entity[0]);
|
||||
if(ec->type == Entity::Type::CIRCLE) {
|
||||
|
|
|
@ -462,7 +462,7 @@ void Entity::GenerateBezierCurves(SBezierList *sbl) const {
|
|||
|
||||
// Record our style for all of the Beziers that we just created.
|
||||
for(; i < sbl->l.n; i++) {
|
||||
sbl->l[i].auxA = style.v;
|
||||
sbl->l[i].auxA = Style::ForEntity(h).v;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -207,7 +207,6 @@ void SolveSpaceUI::ExportViewOrWireframeTo(const Platform::Path &filename, bool
|
|||
for(auto &entity : SK.entity) {
|
||||
Entity *e = &entity;
|
||||
if(!e->IsVisible()) continue;
|
||||
if(e->construction) continue;
|
||||
|
||||
if(SS.exportPwlCurves || sm || fabs(SS.exportOffset) > LENGTH_EPS)
|
||||
{
|
||||
|
@ -735,9 +734,7 @@ void VectorFileWriter::OutputLinesAndMesh(SBezierLoopSetSet *sblss, SMesh *sm) {
|
|||
if(sblss) {
|
||||
SBezierLoopSet *sbls;
|
||||
for(sbls = sblss->l.First(); sbls; sbls = sblss->l.NextAfter(sbls)) {
|
||||
SBezierLoop *sbl;
|
||||
sbl = sbls->l.First();
|
||||
if(!sbl) continue;
|
||||
for(SBezierLoop *sbl = sbls->l.First(); sbl; sbl = sbls->l.NextAfter(sbl)) {
|
||||
b = sbl->l.First();
|
||||
if(!b || !Style::Exportable(b->auxA)) continue;
|
||||
|
||||
|
@ -748,14 +745,13 @@ void VectorFileWriter::OutputLinesAndMesh(SBezierLoopSetSet *sblss, SMesh *sm) {
|
|||
RgbaColor fillRgb = Style::FillColor(hs, /*forExport=*/true);
|
||||
|
||||
StartPath(strokeRgb, lineWidth, stl->filled, fillRgb, hs);
|
||||
for(sbl = sbls->l.First(); sbl; sbl = sbls->l.NextAfter(sbl)) {
|
||||
for(b = sbl->l.First(); b; b = sbl->l.NextAfter(b)) {
|
||||
Bezier(b);
|
||||
}
|
||||
}
|
||||
FinishPath(strokeRgb, lineWidth, stl->filled, fillRgb, hs);
|
||||
}
|
||||
}
|
||||
}
|
||||
FinishAndCloseFile();
|
||||
}
|
||||
|
||||
|
|
|
@ -1083,17 +1083,18 @@ void SvgFileWriter::StartFile() {
|
|||
double sw = max(ptMax.x - ptMin.x, ptMax.y - ptMin.y) / 1000;
|
||||
fprintf(f, "stroke-width:%f;\r\n", sw);
|
||||
fprintf(f, "}\r\n");
|
||||
for(auto &style : SK.style) {
|
||||
Style *s = &style;
|
||||
|
||||
RgbaColor strokeRgb = Style::Color(s->h, /*forExport=*/true);
|
||||
StipplePattern pattern = Style::PatternType(s->h);
|
||||
double stippleScale = Style::StippleScaleMm(s->h);
|
||||
auto export_style = [&](hStyle hs) {
|
||||
Style *s = Style::Get(hs);
|
||||
RgbaColor strokeRgb = Style::Color(hs, /*forExport=*/true);
|
||||
RgbaColor fillRgb = Style::FillColor(hs, /*forExport=*/true);
|
||||
StipplePattern pattern = Style::PatternType(hs);
|
||||
double stippleScale = Style::StippleScaleMm(hs);
|
||||
|
||||
fprintf(f, ".s%x {\r\n", s->h.v);
|
||||
fprintf(f, ".s%x {\r\n", hs.v);
|
||||
fprintf(f, "stroke:#%02x%02x%02x;\r\n", strokeRgb.red, strokeRgb.green, strokeRgb.blue);
|
||||
// don't know why we have to take a half of the width
|
||||
fprintf(f, "stroke-width:%f;\r\n", Style::WidthMm(s->h.v) / 2.0);
|
||||
fprintf(f, "stroke-width:%f;\r\n", Style::WidthMm(hs.v) / 2.0);
|
||||
fprintf(f, "stroke-linecap:round;\r\n");
|
||||
fprintf(f, "stroke-linejoin:round;\r\n");
|
||||
std::string patternStr = MakeStipplePattern(pattern, stippleScale, ',',
|
||||
|
@ -1101,8 +1102,19 @@ void SvgFileWriter::StartFile() {
|
|||
if(!patternStr.empty()) {
|
||||
fprintf(f, "stroke-dasharray:%s;\r\n", patternStr.c_str());
|
||||
}
|
||||
if(s->filled) {
|
||||
fprintf(f, "fill:#%02x%02x%02x;\r\n", fillRgb.red, fillRgb.green, fillRgb.blue);
|
||||
}
|
||||
else {
|
||||
fprintf(f, "fill:none;\r\n");
|
||||
}
|
||||
fprintf(f, "}\r\n");
|
||||
};
|
||||
|
||||
export_style({Style::NO_STYLE});
|
||||
for(auto &style : SK.style) {
|
||||
Style *s = &style;
|
||||
export_style(s->h);
|
||||
}
|
||||
fprintf(f, "]]></style>\r\n");
|
||||
}
|
||||
|
|
|
@ -1304,6 +1304,20 @@ c:
|
|||
break;
|
||||
|
||||
case Command::CONSTRUCTION: {
|
||||
// if we are drawing
|
||||
if(SS.GW.pending.operation == Pending::DRAGGING_NEW_POINT ||
|
||||
SS.GW.pending.operation == Pending::DRAGGING_NEW_LINE_POINT ||
|
||||
SS.GW.pending.operation == Pending::DRAGGING_NEW_ARC_POINT ||
|
||||
SS.GW.pending.operation == Pending::DRAGGING_NEW_CUBIC_POINT ||
|
||||
SS.GW.pending.operation == Pending::DRAGGING_NEW_RADIUS) {
|
||||
for(auto &hr : SS.GW.pending.requests) {
|
||||
Request* r = SK.GetRequest(hr);
|
||||
r->construction = !(r->construction);
|
||||
SS.MarkGroupDirty(r->group);
|
||||
}
|
||||
SS.GW.Invalidate();
|
||||
break;
|
||||
}
|
||||
SS.GW.GroupSelection();
|
||||
if(SS.GW.gs.entities == 0) {
|
||||
Error(_("No entities are selected. Select entities before "
|
||||
|
|
|
@ -270,15 +270,16 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
|||
return;
|
||||
}
|
||||
|
||||
// We're currently dragging something; so do that. But if we haven't
|
||||
// painted since the last time we solved, do nothing, because there's
|
||||
// no sense solving a frame and not displaying it.
|
||||
if(!havePainted) {
|
||||
if(pending.operation == Pending::DRAGGING_POINTS && ctrlDown) {
|
||||
SS.extraLine.ptA = UnProjectPoint(orig.mouseOnButtonDown);
|
||||
SS.extraLine.ptB = UnProjectPoint(mp);
|
||||
SS.extraLine.draw = true;
|
||||
}
|
||||
|
||||
// We're currently dragging something; so do that. But if we haven't
|
||||
// painted since the last time we solved, do nothing, because there's
|
||||
// no sense solving a frame and not displaying it.
|
||||
if(!havePainted) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -319,9 +320,8 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
|||
// Don't start dragging the position about the normal
|
||||
// until we're a little ways out, to get a reasonable
|
||||
// reference pos
|
||||
orig.mouse = mp;
|
||||
break;
|
||||
}
|
||||
qt = Quaternion::IDENTITY;
|
||||
} else {
|
||||
double theta = atan2(orig.mouse.y-orig.mouseOnButtonDown.y,
|
||||
orig.mouse.x-orig.mouseOnButtonDown.x);
|
||||
theta -= atan2(y-orig.mouseOnButtonDown.y,
|
||||
|
@ -329,10 +329,7 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
|||
|
||||
Vector gn = projRight.Cross(projUp);
|
||||
qt = Quaternion::From(gn, -theta);
|
||||
|
||||
SS.extraLine.draw = true;
|
||||
SS.extraLine.ptA = UnProjectPoint(orig.mouseOnButtonDown);
|
||||
SS.extraLine.ptB = UnProjectPoint(mp);
|
||||
}
|
||||
} else {
|
||||
double dx = -(x - orig.mouse.x);
|
||||
double dy = -(y - orig.mouse.y);
|
||||
|
@ -340,7 +337,6 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
|||
qt = Quaternion::From(projUp, -s*dx).Times(
|
||||
Quaternion::From(projRight, s*dy));
|
||||
}
|
||||
orig.mouse = mp;
|
||||
|
||||
// Now apply this rotation to the points being dragged.
|
||||
List<hEntity> *lhe = &(pending.points);
|
||||
|
@ -353,11 +349,10 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
|||
p = qt.Rotate(p);
|
||||
p = p.Plus(SS.extraLine.ptA);
|
||||
e->PointForceTo(p);
|
||||
SS.MarkGroupDirtyByEntity(e->h);
|
||||
} else {
|
||||
UpdateDraggedPoint(*he, x, y);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
} else {
|
||||
Quaternion q = e->PointGetQuaternion();
|
||||
Vector p = e->PointGetNum();
|
||||
q = qt.Times(q);
|
||||
|
@ -365,6 +360,7 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
|||
// Let's rotate about the selected point; so fix up the
|
||||
// translation so that that point didn't move.
|
||||
e->PointForceTo(p);
|
||||
}
|
||||
SS.MarkGroupDirtyByEntity(e->h);
|
||||
}
|
||||
} else {
|
||||
|
@ -373,8 +369,8 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
|||
UpdateDraggedPoint(*he, x, y);
|
||||
SS.MarkGroupDirtyByEntity(*he);
|
||||
}
|
||||
orig.mouse = mp;
|
||||
}
|
||||
orig.mouse = mp;
|
||||
break;
|
||||
|
||||
case Pending::DRAGGING_NEW_CUBIC_POINT: {
|
||||
|
@ -1042,6 +1038,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my, bool shiftDown, bool ct
|
|||
ConstrainPointByHovered(hr.entity(1), &mouse);
|
||||
|
||||
ClearSuper();
|
||||
AddToPending(hr);
|
||||
|
||||
pending.operation = Pending::DRAGGING_NEW_RADIUS;
|
||||
pending.circle = hr.entity(0);
|
||||
|
|
|
@ -963,16 +963,17 @@ public:
|
|||
}
|
||||
|
||||
void SetCursor(Cursor cursor) override {
|
||||
Gdk::CursorType gdkCursorType;
|
||||
std::string cursor_name;
|
||||
switch(cursor) {
|
||||
case Cursor::POINTER: gdkCursorType = Gdk::ARROW; break;
|
||||
case Cursor::HAND: gdkCursorType = Gdk::HAND1; break;
|
||||
case Cursor::POINTER: cursor_name = "default"; break;
|
||||
case Cursor::HAND: cursor_name = "pointer"; break;
|
||||
default: ssassert(false, "Unexpected cursor");
|
||||
}
|
||||
|
||||
auto gdkWindow = gtkWindow.get_gl_widget().get_window();
|
||||
if(gdkWindow) {
|
||||
gdkWindow->set_cursor(Gdk::Cursor::create(gdkCursorType));
|
||||
gdkWindow->set_cursor(Gdk::Cursor::create(gdkWindow->get_display(), cursor_name.c_str()));
|
||||
// gdkWindow->get_display()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -142,7 +142,18 @@ static std::string NegateMnemonics(const std::string &label) {
|
|||
return newLabel;
|
||||
}
|
||||
|
||||
static int Clamp(int x, int a, int b) {
|
||||
static int Clamp(int x, int a, int b, int brda, int brdb) {
|
||||
// If we are outside of an edge of the monitor
|
||||
// and a "border" is requested "move in" from that edge
|
||||
// by "b/brdX" (the "b" parameter is the resolution)
|
||||
if((x <= a) && (brda)) {
|
||||
a += b / brda; // yes "b/brda" since b is the size
|
||||
}
|
||||
|
||||
if(((x >= b) && brdb)) {
|
||||
b -= b / brdb;
|
||||
}
|
||||
|
||||
return max(a, min(x, b));
|
||||
}
|
||||
|
||||
|
@ -1084,7 +1095,7 @@ public:
|
|||
return 0;
|
||||
}
|
||||
} else if(wParam == VK_ESCAPE) {
|
||||
sscheck(SendMessageW(hWindow, msg, wParam, lParam));
|
||||
window->HideEditor();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1218,11 +1229,14 @@ public:
|
|||
sscheck(GetMonitorInfo(MonitorFromRect(&rc, MONITOR_DEFAULTTONEAREST), &mi));
|
||||
|
||||
// If it somehow ended up off-screen, then put it back.
|
||||
// and make it visible by at least this portion of the scrren
|
||||
const LONG movein = 40;
|
||||
|
||||
RECT mrc = mi.rcMonitor;
|
||||
rc.left = Clamp(rc.left, mrc.left, mrc.right);
|
||||
rc.right = Clamp(rc.right, mrc.left, mrc.right);
|
||||
rc.top = Clamp(rc.top, mrc.top, mrc.bottom);
|
||||
rc.bottom = Clamp(rc.bottom, mrc.top, mrc.bottom);
|
||||
rc.left = Clamp(rc.left, mrc.left, mrc.right, 0, movein);
|
||||
rc.right = Clamp(rc.right, mrc.left, mrc.right, movein, 0);
|
||||
rc.top = Clamp(rc.top, mrc.top, mrc.bottom, 0, movein);
|
||||
rc.bottom = Clamp(rc.bottom, mrc.top, mrc.bottom, movein, 0);
|
||||
|
||||
// And make sure the minimum size is respected. (We can freeze a size smaller
|
||||
// than minimum size if the DPI changed between runs.)
|
||||
|
|
|
@ -790,9 +790,9 @@ public:
|
|||
static hConstraint TryConstrain(Constraint::Type type, hEntity ptA, hEntity ptB,
|
||||
hEntity entityA, hEntity entityB = Entity::NO_ENTITY,
|
||||
bool other = false, bool other2 = false);
|
||||
static void ConstrainArcLineTangent(Constraint *c, Entity *line, Entity *arc);
|
||||
static void ConstrainCubicLineTangent(Constraint *c, Entity *line, Entity *cubic);
|
||||
static void ConstrainCurveCurveTangent(Constraint *c, Entity *eA, Entity *eB);
|
||||
static bool ConstrainArcLineTangent(Constraint *c, Entity *line, Entity *arc);
|
||||
static bool ConstrainCubicLineTangent(Constraint *c, Entity *line, Entity *cubic);
|
||||
static bool ConstrainCurveCurveTangent(Constraint *c, Entity *eA, Entity *eB);
|
||||
};
|
||||
|
||||
class hEquation {
|
||||
|
@ -883,6 +883,7 @@ public:
|
|||
RgbaColor color;
|
||||
double width;
|
||||
int zIndex;
|
||||
bool exportable;
|
||||
} Default;
|
||||
static const Default Defaults[];
|
||||
|
||||
|
@ -890,6 +891,7 @@ public:
|
|||
static std::string CnfWidth(const std::string &prefix);
|
||||
static std::string CnfTextHeight(const std::string &prefix);
|
||||
static std::string CnfPrefixToName(const std::string &prefix);
|
||||
static std::string CnfExportable(const std::string &prefix);
|
||||
|
||||
static void CreateAllDefaultStyles();
|
||||
static void CreateDefaultStyle(hStyle h);
|
||||
|
|
|
@ -8,22 +8,22 @@
|
|||
#include "solvespace.h"
|
||||
|
||||
const Style::Default Style::Defaults[] = {
|
||||
{ { ACTIVE_GRP }, "ActiveGrp", RGBf(1.0, 1.0, 1.0), 1.5, 4 },
|
||||
{ { CONSTRUCTION }, "Construction", RGBf(0.1, 0.7, 0.1), 1.5, 0 },
|
||||
{ { INACTIVE_GRP }, "InactiveGrp", RGBf(0.5, 0.3, 0.0), 1.5, 3 },
|
||||
{ { DATUM }, "Datum", RGBf(0.0, 0.8, 0.0), 1.5, 0 },
|
||||
{ { SOLID_EDGE }, "SolidEdge", RGBf(0.8, 0.8, 0.8), 1.0, 2 },
|
||||
{ { CONSTRAINT }, "Constraint", RGBf(1.0, 0.1, 1.0), 1.0, 0 },
|
||||
{ { SELECTED }, "Selected", RGBf(1.0, 0.0, 0.0), 1.5, 0 },
|
||||
{ { HOVERED }, "Hovered", RGBf(1.0, 1.0, 0.0), 1.5, 0 },
|
||||
{ { CONTOUR_FILL }, "ContourFill", RGBf(0.0, 0.1, 0.1), 1.0, 0 },
|
||||
{ { NORMALS }, "Normals", RGBf(0.0, 0.4, 0.4), 1.0, 0 },
|
||||
{ { ANALYZE }, "Analyze", RGBf(0.0, 1.0, 1.0), 3.0, 0 },
|
||||
{ { DRAW_ERROR }, "DrawError", RGBf(1.0, 0.0, 0.0), 8.0, 0 },
|
||||
{ { DIM_SOLID }, "DimSolid", RGBf(0.1, 0.1, 0.1), 1.0, 0 },
|
||||
{ { HIDDEN_EDGE }, "HiddenEdge", RGBf(0.8, 0.8, 0.8), 1.0, 1 },
|
||||
{ { OUTLINE }, "Outline", RGBf(0.8, 0.8, 0.8), 3.0, 5 },
|
||||
{ { 0 }, NULL, RGBf(0.0, 0.0, 0.0), 0.0, 0 }
|
||||
{ { ACTIVE_GRP }, "ActiveGrp", RGBf(1.0, 1.0, 1.0), 1.5, 4, true },
|
||||
{ { CONSTRUCTION }, "Construction", RGBf(0.1, 0.7, 0.1), 1.5, 0, false },
|
||||
{ { INACTIVE_GRP }, "InactiveGrp", RGBf(0.5, 0.3, 0.0), 1.5, 3, true },
|
||||
{ { DATUM }, "Datum", RGBf(0.0, 0.8, 0.0), 1.5, 0, true },
|
||||
{ { SOLID_EDGE }, "SolidEdge", RGBf(0.8, 0.8, 0.8), 1.0, 2, true },
|
||||
{ { CONSTRAINT }, "Constraint", RGBf(1.0, 0.1, 1.0), 1.0, 0, true },
|
||||
{ { SELECTED }, "Selected", RGBf(1.0, 0.0, 0.0), 1.5, 0, true },
|
||||
{ { HOVERED }, "Hovered", RGBf(1.0, 1.0, 0.0), 1.5, 0, true },
|
||||
{ { CONTOUR_FILL }, "ContourFill", RGBf(0.0, 0.1, 0.1), 1.0, 0, true },
|
||||
{ { NORMALS }, "Normals", RGBf(0.0, 0.4, 0.4), 1.0, 0, true },
|
||||
{ { ANALYZE }, "Analyze", RGBf(0.0, 1.0, 1.0), 3.0, 0, true },
|
||||
{ { DRAW_ERROR }, "DrawError", RGBf(1.0, 0.0, 0.0), 8.0, 0, true },
|
||||
{ { DIM_SOLID }, "DimSolid", RGBf(0.1, 0.1, 0.1), 1.0, 0, true },
|
||||
{ { HIDDEN_EDGE }, "HiddenEdge", RGBf(0.8, 0.8, 0.8), 1.0, 1, true },
|
||||
{ { OUTLINE }, "Outline", RGBf(0.8, 0.8, 0.8), 3.0, 5, true },
|
||||
{ { 0 }, NULL, RGBf(0.0, 0.0, 0.0), 0.0, 0, true }
|
||||
};
|
||||
|
||||
std::string Style::CnfColor(const std::string &prefix) {
|
||||
|
@ -35,6 +35,9 @@ std::string Style::CnfWidth(const std::string &prefix) {
|
|||
std::string Style::CnfTextHeight(const std::string &prefix) {
|
||||
return "Style_" + prefix + "_TextHeight";
|
||||
}
|
||||
std::string Style::CnfExportable(const std::string &prefix) {
|
||||
return "Style_" + prefix + "_Exportable";
|
||||
}
|
||||
|
||||
std::string Style::CnfPrefixToName(const std::string &prefix) {
|
||||
std::string name = "#def-";
|
||||
|
@ -97,7 +100,9 @@ void Style::FillDefaultStyle(Style *s, const Default *d, bool factory) {
|
|||
s->textOrigin = TextOrigin::NONE;
|
||||
s->textAngle = 0;
|
||||
s->visible = true;
|
||||
s->exportable = true;
|
||||
s->exportable = (factory)
|
||||
? d->exportable
|
||||
: settings->ThawBool(CnfExportable(d->cnfPrefix), d->exportable);
|
||||
s->filled = false;
|
||||
s->fillColor = RGBf(0.3, 0.3, 0.3);
|
||||
s->stippleType = (d->h.v == Style::HIDDEN_EDGE) ? StipplePattern::DASH
|
||||
|
@ -121,6 +126,7 @@ void Style::FreezeDefaultStyles(Platform::SettingsRef settings) {
|
|||
settings->FreezeColor(CnfColor(d->cnfPrefix), Color(d->h));
|
||||
settings->FreezeFloat(CnfWidth(d->cnfPrefix), (float)Width(d->h));
|
||||
settings->FreezeFloat(CnfTextHeight(d->cnfPrefix), (float)TextHeight(d->h));
|
||||
settings->FreezeBool(CnfExportable(d->cnfPrefix), Exportable(d->h.v));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -850,17 +856,19 @@ void TextWindow::ShowStyleInfo() {
|
|||
((uint32_t)s->textOrigin & (uint32_t)Style::TextOrigin::TOP) ? RADIO_TRUE : RADIO_FALSE);
|
||||
}
|
||||
|
||||
if(s->h.v >= Style::FIRST_CUSTOM) {
|
||||
Printf(false, "");
|
||||
|
||||
if(s->h.v >= Style::FIRST_CUSTOM) {
|
||||
Printf(false, " %Fd%D%f%Lv%s show these objects on screen%E",
|
||||
s->h.v, &ScreenChangeStyleYesNo,
|
||||
s->visible ? CHECK_TRUE : CHECK_FALSE);
|
||||
}
|
||||
|
||||
Printf(false, " %Fd%D%f%Le%s export these objects%E",
|
||||
s->h.v, &ScreenChangeStyleYesNo,
|
||||
s->exportable ? CHECK_TRUE : CHECK_FALSE);
|
||||
|
||||
if(s->h.v >= Style::FIRST_CUSTOM) {
|
||||
Printf(false, "");
|
||||
Printf(false, "To assign lines or curves to this style,");
|
||||
Printf(false, "right-click them on the drawing.");
|
||||
|
|