Add an option to display areas of closed contours.

This is useful e.g. for architectural work.
pull/238/head
EvilSpirit 2017-03-30 21:39:42 +07:00 committed by whitequark
parent c0b6eaa935
commit 99f6ea34f1
14 changed files with 594 additions and 0 deletions

View File

@ -49,6 +49,7 @@ New measurement/analysis features:
"Analyze → Measure Perimeter".
* New command for measuring center of mass, with live updates as the sketch
changes, "Analyze → Center of Mass".
* New option for displaying areas of closed contours.
* When selecting a point and a line, projected distance to to current
workplane is displayed.

View File

@ -84,6 +84,11 @@ void TextWindow::ScreenChangeBackFaces(int link, uint32_t v) {
InvalidateGraphics();
}
void TextWindow::ScreenChangeShowContourAreas(int link, uint32_t v) {
SS.showContourAreas = !SS.showContourAreas;
InvalidateGraphics();
}
void TextWindow::ScreenChangeCheckClosedContour(int link, uint32_t v) {
SS.checkClosedContour = !SS.checkClosedContour;
InvalidateGraphics();
@ -297,6 +302,9 @@ void TextWindow::ShowConfiguration() {
Printf(false, " %Fd%f%Ll%s check sketch for closed contour%E",
&ScreenChangeCheckClosedContour,
SS.checkClosedContour ? CHECK_TRUE : CHECK_FALSE);
Printf(false, " %Fd%f%Ll%s show areas of closed contours%E",
&ScreenChangeShowContourAreas,
SS.showContourAreas ? CHECK_TRUE : CHECK_FALSE);
Printf(false, "");
Printf(false, "%Ft autosave interval (in minutes)%E");

View File

@ -693,6 +693,16 @@ void GraphicsWindow::Draw(Canvas *canvas) {
c.Draw(Constraint::DrawAs::DEFAULT, canvas);
}
// Draw areas
if(SS.showContourAreas) {
for(hGroup hg : SK.groupOrder) {
Group *g = SK.GetGroup(hg);
if(g->h.v != activeGroup.v) continue;
if(!(g->IsVisible())) continue;
g->DrawContourAreaLabels(canvas);
}
}
// Draw the "pending" constraint, i.e. a constraint that would be
// placed on a line that is almost horizontal or vertical.
if(SS.GW.pending.operation == Pending::DRAGGING_NEW_LINE_POINT &&

View File

@ -677,3 +677,38 @@ void Group::DrawFilledPaths(Canvas *canvas) {
}
}
void Group::DrawContourAreaLabels(Canvas *canvas) {
const Camera &camera = canvas->GetCamera();
Vector gr = camera.projRight.ScaledBy(1 / camera.scale);
Vector gu = camera.projUp.ScaledBy(1 / camera.scale);
for(SBezierLoopSet &sbls : bezierLoops.l) {
if(sbls.l.n == 0 || sbls.l.elem[0].l.n == 0) continue;
Vector min = sbls.l.elem[0].l.elem[0].ctrl[0];
Vector max = min;
Vector zero = Vector::From(0.0, 0.0, 0.0);
sbls.GetBoundingProjd(Vector::From(1.0, 0.0, 0.0), zero, &min.x, &max.x);
sbls.GetBoundingProjd(Vector::From(0.0, 1.0, 0.0), zero, &min.y, &max.y);
sbls.GetBoundingProjd(Vector::From(0.0, 0.0, 1.0), zero, &min.z, &max.z);
Vector mid = min.Plus(max).ScaledBy(0.5);
hStyle hs = { Style::CONSTRAINT };
Canvas::Stroke stroke = Style::Stroke(hs);
stroke.layer = Canvas::Layer::FRONT;
double scale = SS.MmPerUnit();
std::string label = ssprintf("%.3f %s²",
fabs(sbls.SignedArea() / (scale * scale)),
SS.UnitName());
double fontHeight = Style::TextHeight(hs);
double textWidth = VectorFont::Builtin()->GetWidth(fontHeight, label),
textHeight = VectorFont::Builtin()->GetCapHeight(fontHeight);
Vector pos = mid.Minus(gr.ScaledBy(textWidth / 2.0))
.Minus(gu.ScaledBy(textHeight / 2.0));
canvas->DrawVectorText(label, fontHeight, pos, gr, gu, canvas->GetStroke(stroke));
}
}

View File

@ -287,6 +287,7 @@ public:
void Draw(Canvas *canvas);
void DrawPolyError(Canvas *canvas);
void DrawFilledPaths(Canvas *canvas);
void DrawContourAreaLabels(Canvas *canvas);
SPolygon GetPolygon();

View File

@ -70,6 +70,8 @@ void SolveSpaceUI::Init() {
drawBackFaces = CnfThawBool(true, "DrawBackFaces");
// Check that contours are closed and not self-intersecting
checkClosedContour = CnfThawBool(true, "CheckClosedContour");
// Draw closed polygons areas
showContourAreas = CnfThawBool(false, "ShowContourAreas");
// Export shaded triangles in a 2d view
exportShadedTriangles = CnfThawBool(true, "ExportShadedTriangles");
// Export pwl curves (instead of exact) always
@ -191,6 +193,8 @@ void SolveSpaceUI::Exit() {
CnfFreezeBool(fixExportColors, "FixExportColors");
// Draw back faces of triangles (when mesh is leaky/self-intersecting)
CnfFreezeBool(drawBackFaces, "DrawBackFaces");
// Draw closed polygons areas
CnfFreezeBool(showContourAreas, "ShowContourAreas");
// Check that contours are closed and not self-intersecting
CnfFreezeBool(checkClosedContour, "CheckClosedContour");
// Export shaded triangles in a 2d view

View File

@ -651,6 +651,7 @@ public:
float exportOffset;
bool fixExportColors;
bool drawBackFaces;
bool showContourAreas;
bool checkClosedContour;
bool showToolbar;
Platform::Path screenshotFile;

View File

@ -536,6 +536,17 @@ void SBezierLoopSet::GetBoundingProjd(Vector u, Vector orig,
}
}
double SBezierLoopSet::SignedArea() {
if(EXACT(area == 0.0)) {
SPolygon sp = {};
MakePwlInto(&sp);
sp.normal = sp.ComputeNormal();
area = sp.SignedArea();
sp.Clear();
}
return area;
}
//-----------------------------------------------------------------------------
// Convert all the Beziers into piecewise linear form, and assemble that into
// a polygon, one contour per loop.

View File

@ -151,6 +151,7 @@ public:
List<SBezierLoop> l;
Vector normal;
Vector point;
double area;
static SBezierLoopSet From(SBezierList *spcl, SPolygon *poly,
double chordTol,
@ -158,6 +159,7 @@ public:
SBezierList *openContours);
void GetBoundingProjd(Vector u, Vector orig, double *umin, double *umax) const;
double SignedArea();
void MakePwlInto(SPolygon *sp) const;
void Clear();
};

View File

@ -517,6 +517,7 @@ public:
static void ScreenChangeFixExportColors(int link, uint32_t v);
static void ScreenChangeBackFaces(int link, uint32_t v);
static void ScreenChangeShowContourAreas(int link, uint32_t v);
static void ScreenChangeCheckClosedContour(int link, uint32_t v);
static void ScreenChangePwlCurves(int link, uint32_t v);
static void ScreenChangeCanvasSizeAuto(int link, uint32_t v);

View File

@ -11,6 +11,7 @@ endforeach()
set(testsuite_SOURCES
harness.cpp
analysis/contour_area/test.cpp
core/expr/test.cpp
core/locale/test.cpp
core/path/test.cpp

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -0,0 +1,512 @@
±²³SolveSpaceREVa
Group.h.v=00000001
Group.type=5000
Group.name=#references
Group.color=ff000000
Group.skipFirst=0
Group.predef.swapUV=0
Group.predef.negateU=0
Group.predef.negateV=0
Group.visible=1
Group.suppress=0
Group.relaxConstraints=0
Group.allowRedundant=0
Group.allDimsReference=0
Group.scale=1.00000000000000000000
Group.remap={
}
AddGroup
Group.h.v=00000002
Group.type=5001
Group.order=1
Group.name=sketch-in-plane
Group.activeWorkplane.v=80020000
Group.color=ff000000
Group.subtype=6000
Group.skipFirst=0
Group.predef.q.w=1.00000000000000000000
Group.predef.origin.v=00010001
Group.predef.swapUV=0
Group.predef.negateU=0
Group.predef.negateV=0
Group.visible=1
Group.suppress=0
Group.relaxConstraints=0
Group.allowRedundant=0
Group.allDimsReference=0
Group.scale=1.00000000000000000000
Group.remap={
}
AddGroup
Param.h.v.=00010010
AddParam
Param.h.v.=00010011
AddParam
Param.h.v.=00010012
AddParam
Param.h.v.=00010020
Param.val=1.00000000000000000000
AddParam
Param.h.v.=00010021
AddParam
Param.h.v.=00010022
AddParam
Param.h.v.=00010023
AddParam
Param.h.v.=00020010
AddParam
Param.h.v.=00020011
AddParam
Param.h.v.=00020012
AddParam
Param.h.v.=00020020
Param.val=0.50000000000000000000
AddParam
Param.h.v.=00020021
Param.val=0.50000000000000000000
AddParam
Param.h.v.=00020022
Param.val=0.50000000000000000000
AddParam
Param.h.v.=00020023
Param.val=0.50000000000000000000
AddParam
Param.h.v.=00030010
AddParam
Param.h.v.=00030011
AddParam
Param.h.v.=00030012
AddParam
Param.h.v.=00030020
Param.val=0.50000000000000000000
AddParam
Param.h.v.=00030021
Param.val=-0.50000000000000000000
AddParam
Param.h.v.=00030022
Param.val=-0.50000000000000000000
AddParam
Param.h.v.=00030023
Param.val=-0.50000000000000000000
AddParam
Param.h.v.=00040010
Param.val=10.00000000000000000000
AddParam
Param.h.v.=00040011
Param.val=-10.00000000000000000000
AddParam
Param.h.v.=00040013
Param.val=10.00000000000000000000
AddParam
Param.h.v.=00040014
Param.val=10.00000000000000000000
AddParam
Param.h.v.=00050010
Param.val=-10.00000000000000000000
AddParam
Param.h.v.=00050011
Param.val=-10.00000000000000000000
AddParam
Param.h.v.=00050013
Param.val=10.00000000000000000000
AddParam
Param.h.v.=00050014
Param.val=-10.00000000000000000000
AddParam
Param.h.v.=00060010
Param.val=-10.00000000000000000000
AddParam
Param.h.v.=00060011
Param.val=10.00000000000000000000
AddParam
Param.h.v.=00060013
Param.val=-10.00000000000000000000
AddParam
Param.h.v.=00060014
Param.val=-10.00000000000000000000
AddParam
Param.h.v.=00070010
Param.val=10.00000000000000000000
AddParam
Param.h.v.=00070011
Param.val=10.00000000000000000000
AddParam
Param.h.v.=00070013
Param.val=-10.00000000000000000000
AddParam
Param.h.v.=00070014
Param.val=10.00000000000000000000
AddParam
Request.h.v=00000001
Request.type=100
Request.group.v=00000001
Request.construction=0
AddRequest
Request.h.v=00000002
Request.type=100
Request.group.v=00000001
Request.construction=0
AddRequest
Request.h.v=00000003
Request.type=100
Request.group.v=00000001
Request.construction=0
AddRequest
Request.h.v=00000004
Request.type=200
Request.workplane.v=80020000
Request.group.v=00000002
Request.construction=0
AddRequest
Request.h.v=00000005
Request.type=200
Request.workplane.v=80020000
Request.group.v=00000002
Request.construction=0
AddRequest
Request.h.v=00000006
Request.type=200
Request.workplane.v=80020000
Request.group.v=00000002
Request.construction=0
AddRequest
Request.h.v=00000007
Request.type=200
Request.workplane.v=80020000
Request.group.v=00000002
Request.construction=0
AddRequest
Entity.h.v=00010000
Entity.type=10000
Entity.construction=0
Entity.point[0].v=00010001
Entity.normal.v=00010020
Entity.actVisible=1
AddEntity
Entity.h.v=00010001
Entity.type=2000
Entity.construction=1
Entity.actVisible=1
AddEntity
Entity.h.v=00010020
Entity.type=3000
Entity.construction=0
Entity.point[0].v=00010001
Entity.actNormal.w=1.00000000000000000000
Entity.actVisible=1
AddEntity
Entity.h.v=00020000
Entity.type=10000
Entity.construction=0
Entity.point[0].v=00020001
Entity.normal.v=00020020
Entity.actVisible=1
AddEntity
Entity.h.v=00020001
Entity.type=2000
Entity.construction=1
Entity.actVisible=1
AddEntity
Entity.h.v=00020020
Entity.type=3000
Entity.construction=0
Entity.point[0].v=00020001
Entity.actNormal.w=0.50000000000000000000
Entity.actNormal.vx=0.50000000000000000000
Entity.actNormal.vy=0.50000000000000000000
Entity.actNormal.vz=0.50000000000000000000
Entity.actVisible=1
AddEntity
Entity.h.v=00030000
Entity.type=10000
Entity.construction=0
Entity.point[0].v=00030001
Entity.normal.v=00030020
Entity.actVisible=1
AddEntity
Entity.h.v=00030001
Entity.type=2000
Entity.construction=1
Entity.actVisible=1
AddEntity
Entity.h.v=00030020
Entity.type=3000
Entity.construction=0
Entity.point[0].v=00030001
Entity.actNormal.w=0.50000000000000000000
Entity.actNormal.vx=-0.50000000000000000000
Entity.actNormal.vy=-0.50000000000000000000
Entity.actNormal.vz=-0.50000000000000000000
Entity.actVisible=1
AddEntity
Entity.h.v=00040000
Entity.type=11000
Entity.construction=0
Entity.point[0].v=00040001
Entity.point[1].v=00040002
Entity.workplane.v=80020000
Entity.actVisible=1
AddEntity
Entity.h.v=00040001
Entity.type=2001
Entity.construction=0
Entity.workplane.v=80020000
Entity.actPoint.x=10.00000000000000000000
Entity.actPoint.y=-10.00000000000000000000
Entity.actVisible=1
AddEntity
Entity.h.v=00040002
Entity.type=2001
Entity.construction=0
Entity.workplane.v=80020000
Entity.actPoint.x=10.00000000000000000000
Entity.actPoint.y=10.00000000000000000000
Entity.actVisible=1
AddEntity
Entity.h.v=00050000
Entity.type=11000
Entity.construction=0
Entity.point[0].v=00050001
Entity.point[1].v=00050002
Entity.workplane.v=80020000
Entity.actVisible=1
AddEntity
Entity.h.v=00050001
Entity.type=2001
Entity.construction=0
Entity.workplane.v=80020000
Entity.actPoint.x=-10.00000000000000000000
Entity.actPoint.y=-10.00000000000000000000
Entity.actVisible=1
AddEntity
Entity.h.v=00050002
Entity.type=2001
Entity.construction=0
Entity.workplane.v=80020000
Entity.actPoint.x=10.00000000000000000000
Entity.actPoint.y=-10.00000000000000000000
Entity.actVisible=1
AddEntity
Entity.h.v=00060000
Entity.type=11000
Entity.construction=0
Entity.point[0].v=00060001
Entity.point[1].v=00060002
Entity.workplane.v=80020000
Entity.actVisible=1
AddEntity
Entity.h.v=00060001
Entity.type=2001
Entity.construction=0
Entity.workplane.v=80020000
Entity.actPoint.x=-10.00000000000000000000
Entity.actPoint.y=10.00000000000000000000
Entity.actVisible=1
AddEntity
Entity.h.v=00060002
Entity.type=2001
Entity.construction=0
Entity.workplane.v=80020000
Entity.actPoint.x=-10.00000000000000000000
Entity.actPoint.y=-10.00000000000000000000
Entity.actVisible=1
AddEntity
Entity.h.v=00070000
Entity.type=11000
Entity.construction=0
Entity.point[0].v=00070001
Entity.point[1].v=00070002
Entity.workplane.v=80020000
Entity.actVisible=1
AddEntity
Entity.h.v=00070001
Entity.type=2001
Entity.construction=0
Entity.workplane.v=80020000
Entity.actPoint.x=10.00000000000000000000
Entity.actPoint.y=10.00000000000000000000
Entity.actVisible=1
AddEntity
Entity.h.v=00070002
Entity.type=2001
Entity.construction=0
Entity.workplane.v=80020000
Entity.actPoint.x=-10.00000000000000000000
Entity.actPoint.y=10.00000000000000000000
Entity.actVisible=1
AddEntity
Entity.h.v=80020000
Entity.type=10000
Entity.construction=0
Entity.point[0].v=80020002
Entity.normal.v=80020001
Entity.actVisible=1
AddEntity
Entity.h.v=80020001
Entity.type=3010
Entity.construction=0
Entity.point[0].v=80020002
Entity.actNormal.w=1.00000000000000000000
Entity.actVisible=1
AddEntity
Entity.h.v=80020002
Entity.type=2012
Entity.construction=1
Entity.actVisible=1
AddEntity
Constraint.h.v=00000001
Constraint.type=20
Constraint.group.v=00000002
Constraint.workplane.v=80020000
Constraint.ptA.v=00040001
Constraint.ptB.v=00050002
Constraint.other=0
Constraint.other2=0
Constraint.reference=0
AddConstraint
Constraint.h.v=00000002
Constraint.type=20
Constraint.group.v=00000002
Constraint.workplane.v=80020000
Constraint.ptA.v=00050001
Constraint.ptB.v=00060002
Constraint.other=0
Constraint.other2=0
Constraint.reference=0
AddConstraint
Constraint.h.v=00000003
Constraint.type=20
Constraint.group.v=00000002
Constraint.workplane.v=80020000
Constraint.ptA.v=00060001
Constraint.ptB.v=00070002
Constraint.other=0
Constraint.other2=0
Constraint.reference=0
AddConstraint
Constraint.h.v=00000004
Constraint.type=20
Constraint.group.v=00000002
Constraint.workplane.v=80020000
Constraint.ptA.v=00070001
Constraint.ptB.v=00040002
Constraint.other=0
Constraint.other2=0
Constraint.reference=0
AddConstraint
Constraint.h.v=00000005
Constraint.type=81
Constraint.group.v=00000002
Constraint.workplane.v=80020000
Constraint.entityA.v=00040000
Constraint.other=0
Constraint.other2=0
Constraint.reference=0
AddConstraint
Constraint.h.v=00000006
Constraint.type=80
Constraint.group.v=00000002
Constraint.workplane.v=80020000
Constraint.entityA.v=00050000
Constraint.other=0
Constraint.other2=0
Constraint.reference=0
AddConstraint
Constraint.h.v=00000007
Constraint.type=81
Constraint.group.v=00000002
Constraint.workplane.v=80020000
Constraint.entityA.v=00060000
Constraint.other=0
Constraint.other2=0
Constraint.reference=0
AddConstraint
Constraint.h.v=00000008
Constraint.type=80
Constraint.group.v=00000002
Constraint.workplane.v=80020000
Constraint.entityA.v=00070000
Constraint.other=0
Constraint.other2=0
Constraint.reference=0
AddConstraint

View File

@ -0,0 +1,7 @@
#include "harness.h"
TEST_CASE(normal_roundtrip) {
SS.showContourAreas = true;
CHECK_LOAD("normal.slvs");
CHECK_RENDER("normal.png");
}