From c81cbd9ee936159017740468e5e58f509b3305bf Mon Sep 17 00:00:00 2001 From: Jonathan Westhues Date: Mon, 1 Mar 2010 09:23:57 -0800 Subject: [PATCH] Add ability to measure the area of a plane sketch, since that's easy and useful. Also make the volume measurement use Message(), and not a separate text window screen. And make Edit -> Unselect All (Esc) clear the marks drawn to indicate free parameters, since it clears all the other temporary stuff drawn in the graphics window. [git-p4: depot-paths = "//depot/solvespace/": change = 2121] --- graphicswin.cpp | 7 +++++++ polygon.cpp | 17 ++++++++++++++++- polygon.h | 2 ++ solvespace.cpp | 46 +++++++++++++++++++++++++++++++++++++++++++--- textscreens.cpp | 17 ----------------- textwin.cpp | 1 - ui.h | 13 +++++-------- wishlist.txt | 1 - 8 files changed, 73 insertions(+), 31 deletions(-) diff --git a/graphicswin.cpp b/graphicswin.cpp index 1285ce05..9b2d2639 100644 --- a/graphicswin.cpp +++ b/graphicswin.cpp @@ -120,6 +120,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = { { 0, "&Analyze", 0, NULL }, { 1, "Measure &Volume\tCtrl+Shift+V", MNU_VOLUME, 'V'|S|C,mAna }, +{ 1, "Measure &Area\tCtrl+Shift+A", MNU_AREA, 'A'|S|C,mAna }, { 1, "Show &Interfering Parts\tCtrl+Shift+I", MNU_INTERFERENCE, 'I'|S|C,mAna }, { 1, "Show &Naked Edges\tCtrl+Shift+N", MNU_NAKED_EDGES, 'N'|S|C,mAna }, { 1, NULL, 0, NULL }, @@ -631,6 +632,12 @@ void GraphicsWindow::MenuEdit(int id) { HideTextEditControl(); SS.nakedEdges.Clear(); SS.justExportedInfo.draw = false; + // This clears the marks drawn to indicate which points are + // still free to drag. + Param *p; + for(p = SK.param.First(); p; p = SK.param.NextAfter(p)) { + p->free = false; + } break; case MNU_SELECT_ALL: { diff --git a/polygon.cpp b/polygon.cpp index bc2989d9..98cae6c0 100644 --- a/polygon.cpp +++ b/polygon.cpp @@ -548,6 +548,10 @@ bool SContour::IsClockwiseProjdToNormal(Vector n) { // what we do then. if(n.Magnitude() < 0.01) return true; + return (SignedAreaProjdToNormal(n) < 0); +} + +double SContour::SignedAreaProjdToNormal(Vector n) { // An arbitrary 2d coordinate system that has n as its normal Vector u = n.Normal(0); Vector v = n.Normal(1); @@ -561,7 +565,7 @@ bool SContour::IsClockwiseProjdToNormal(Vector n) { area += ((v0 + v1)/2)*(u1 - u0); } - return (area < 0); + return area; } bool SContour::ContainsPointProjdToNormal(Vector n, Vector p) { @@ -621,6 +625,17 @@ Vector SPolygon::ComputeNormal(void) { return (l.elem[0]).ComputeNormal(); } +double SPolygon::SignedArea(void) { + SContour *sc; + double area = 0; + // This returns the true area only if the contours are all oriented + // correctly, with the holes backwards from the outer contours. + for(sc = l.First(); sc; sc = l.NextAfter(sc)) { + area += sc->SignedAreaProjdToNormal(normal); + } + return area; +} + bool SPolygon::ContainsPoint(Vector p) { return (WindingNumberForPoint(p) % 2) == 1; } diff --git a/polygon.h b/polygon.h index 5ba08670..e447d060 100644 --- a/polygon.h +++ b/polygon.h @@ -99,6 +99,7 @@ public: void MakeEdgesInto(SEdgeList *el); void Reverse(void); Vector ComputeNormal(void); + double SignedAreaProjdToNormal(Vector n); bool IsClockwiseProjdToNormal(Vector n); bool ContainsPointProjdToNormal(Vector n, Vector p); void OffsetInto(SContour *dest, double r); @@ -125,6 +126,7 @@ public: Vector ComputeNormal(void); void AddEmptyContour(void); int WindingNumberForPoint(Vector p); + double SignedArea(void); bool ContainsPoint(Vector p); void MakeEdgesInto(SEdgeList *el); void FixContourDirections(void); diff --git a/solvespace.cpp b/solvespace.cpp index 1530a8fe..db902364 100644 --- a/solvespace.cpp +++ b/solvespace.cpp @@ -630,9 +630,49 @@ void SolveSpace::MenuAnalyze(int id) { vol += integral; } - SS.TW.shown.volume = vol; - SS.TW.GoToScreen(TextWindow::SCREEN_MESH_VOLUME); - SS.later.showTW = true; + + char msg[1024]; + sprintf(msg, "The volume of the solid model is:\n\n" + " %.3f %s^3", + vol / pow(SS.MmPerUnit(), 3), + SS.UnitName()); + + if(SS.viewUnits == SolveSpace::UNIT_MM) { + sprintf(msg+strlen(msg), "\n %.2f mL", vol/(10*10*10)); + } + strcpy(msg+strlen(msg), + "\n\nCurved surfaces have been approximated as triangles.\n" + "This introduces error, typically of around 1%."); + Message("%s", msg); + break; + } + + case GraphicsWindow::MNU_AREA: { + Group *g = SK.GetGroup(SS.GW.activeGroup); + if(g->polyError.how != Group::POLY_GOOD) { + Error("This group does not contain a correctly-formed " + "2d closed area. It is open, not coplanar, or self-" + "intersecting."); + break; + } + SEdgeList sel; + ZERO(&sel); + g->polyLoops.MakeEdgesInto(&sel); + SPolygon sp; + ZERO(&sp); + sel.AssemblePolygon(&sp, NULL, true); + sp.normal = sp.ComputeNormal(); + sp.FixContourDirections(); + double area = sp.SignedArea(); + double scale = SS.MmPerUnit(); + Message("The area of the region sketched in this group is:\n\n" + " %.3f %s^2\n\n" + "Curves have been approximated as piecewise linear.\n" + "This introduces error, typically of around 1%%.", + area / (scale*scale), + SS.UnitName()); + sel.Clear(); + sp.Clear(); break; } diff --git a/textscreens.cpp b/textscreens.cpp index 8d66ecc6..8ec5c961 100644 --- a/textscreens.cpp +++ b/textscreens.cpp @@ -674,23 +674,6 @@ void TextWindow::ShowStepDimension(void) { Printf(true, "(or %Fl%Ll%fcancel operation%E)", &ScreenHome); } -//----------------------------------------------------------------------------- -// A report of the volume of the mesh. No interaction, output-only. -//----------------------------------------------------------------------------- -void TextWindow::ShowMeshVolume(void) { - Printf(true, "%FtMESH VOLUME"); - - Printf(true, " %3 %s^3", - shown.volume / pow(SS.MmPerUnit(), 3), - SS.UnitName()); - - if(SS.viewUnits == SolveSpace::UNIT_MM) { - Printf(false, " %2 mL", shown.volume/(10*10*10)); - } - - Printf(true, "%Fl%Ll%f(back)%E", &ScreenHome); -} - //----------------------------------------------------------------------------- // The edit control is visible, and the user just pressed enter. //----------------------------------------------------------------------------- diff --git a/textwin.cpp b/textwin.cpp index d1140d73..8aaa579d 100644 --- a/textwin.cpp +++ b/textwin.cpp @@ -234,7 +234,6 @@ void TextWindow::Show(void) { case SCREEN_GROUP_SOLVE_INFO: ShowGroupSolveInfo(); break; case SCREEN_CONFIGURATION: ShowConfiguration(); break; case SCREEN_STEP_DIMENSION: ShowStepDimension(); break; - case SCREEN_MESH_VOLUME: ShowMeshVolume(); break; case SCREEN_LIST_OF_STYLES: ShowListOfStyles(); break; case SCREEN_STYLE_INFO: ShowStyleInfo(); break; case SCREEN_PASTE_TRANSFORMED: ShowPasteTransformed(); break; diff --git a/ui.h b/ui.h index 1fff381b..afc0df57 100644 --- a/ui.h +++ b/ui.h @@ -51,11 +51,10 @@ public: static const int SCREEN_GROUP_SOLVE_INFO = 2; static const int SCREEN_CONFIGURATION = 3; static const int SCREEN_STEP_DIMENSION = 4; - static const int SCREEN_MESH_VOLUME = 5; - static const int SCREEN_LIST_OF_STYLES = 6; - static const int SCREEN_STYLE_INFO = 7; - static const int SCREEN_PASTE_TRANSFORMED = 8; - static const int SCREEN_EDIT_VIEW = 9; + static const int SCREEN_LIST_OF_STYLES = 5; + static const int SCREEN_STYLE_INFO = 6; + static const int SCREEN_PASTE_TRANSFORMED = 7; + static const int SCREEN_EDIT_VIEW = 8; typedef struct { int screen; @@ -74,8 +73,6 @@ public: Vector origin; double scale; } paste; - - double volume; } ShownState; ShownState shown; @@ -149,7 +146,6 @@ public: void ShowListOfStyles(void); void ShowStyleInfo(void); void ShowStepDimension(void); - void ShowMeshVolume(void); void ShowPasteTransformed(void); void ShowEditView(void); // Special screen, based on selection @@ -330,6 +326,7 @@ public: MNU_COMMENT, // Analyze MNU_VOLUME, + MNU_AREA, MNU_INTERFERENCE, MNU_NAKED_EDGES, MNU_SHOW_DOF, diff --git a/wishlist.txt b/wishlist.txt index bcb3d882..7fcbeefd 100644 --- a/wishlist.txt +++ b/wishlist.txt @@ -1,7 +1,6 @@ replace show/hide links with icons add checked/unchecked checkbox and radio button fix bug with rotation in plane where green line stays displayed -area of sketch in a given workplane (easy, useful) lock point where dragged constraint remove toolbar icons for sketch in 3d, add View -> Align to Workplane