1 /* This file is part of Dilay
2  * Copyright © 2015-2018 Alexander Bau
3  * Use and redistribute under the terms of the GNU General Public License
4  */
5 #include <QCheckBox>
6 #include "cache.hpp"
7 #include "distance.hpp"
8 #include "dynamic/mesh.hpp"
9 #include "isosurface-extraction.hpp"
10 #include "mesh.hpp"
11 #include "primitive/aabox.hpp"
12 #include "primitive/cone-sphere.hpp"
13 #include "scene.hpp"
14 #include "sketch/mesh-intersection.hpp"
15 #include "sketch/mesh.hpp"
16 #include "sketch/path.hpp"
17 #include "state.hpp"
18 #include "tool/sculpt/util/action.hpp"
19 #include "tools.hpp"
20 #include "view/pointing-event.hpp"
21 #include "view/resolution-slider.hpp"
22 #include "view/tool-tip.hpp"
23 #include "view/two-column-grid.hpp"
24 #include "view/util.hpp"
25 
26 struct ToolConvertSketch::Impl
27 {
28   ToolConvertSketch* self;
29   float              resolution;
30 
ImplToolConvertSketch::Impl31   Impl (ToolConvertSketch* s)
32     : self (s)
33     , resolution (s->cache ().get<float> ("resolution", 0.06))
34   {
35   }
36 
runInitializeToolConvertSketch::Impl37   ToolResponse runInitialize ()
38   {
39     this->setupProperties ();
40     this->setupToolTip ();
41 
42     return ToolResponse::Redraw;
43   }
44 
setupPropertiesToolConvertSketch::Impl45   void setupProperties ()
46   {
47     ViewTwoColumnGrid& properties = this->self->properties ();
48 
49     ViewResolutionSlider& resolutionEdit =
50       ViewUtil::resolutionSlider (0.01f, this->resolution, 0.1f);
51     ViewUtil::connect (resolutionEdit, [this](float r) {
52       this->resolution = r;
53       this->self->cache ().set ("resolution", r);
54     });
55     properties.addStacked (QObject::tr ("Resolution"), resolutionEdit);
56   }
57 
setupToolTipToolConvertSketch::Impl58   void setupToolTip ()
59   {
60     ViewToolTip toolTip;
61     toolTip.add (ViewInputEvent::MouseLeft, QObject::tr ("Convert selection"));
62     this->self->state ().setToolTip (&toolTip);
63   }
64 
convertToolConvertSketch::Impl65   DynamicMesh& convert (SketchMesh& sketch)
66   {
67     glm::vec3 min, max;
68     sketch.minMax (min, max);
69 
70     const IsosurfaceExtraction::DistanceCallback getDistance = [&sketch](const glm::vec3& pos) {
71       float distance = Util::maxFloat ();
72 
73       if (sketch.tree ().hasRoot ())
74       {
75         sketch.tree ().root ().forEachConstNode ([&pos, &distance](const SketchNode& node) {
76           const float d =
77             node.parent ()
78               ? Distance::distance (PrimConeSphere (node.data (), node.parent ()->data ()), pos)
79               : Distance::distance (node.data (), pos);
80 
81           distance = glm::min (distance, d);
82         });
83       }
84       for (const SketchPath& p : sketch.paths ())
85       {
86         for (const PrimSphere& s : p.spheres ())
87         {
88           distance = glm::min (distance, Distance::distance (s, pos));
89         }
90       }
91       return distance;
92     };
93 
94     sketch.optimizePaths ();
95     DynamicMesh mesh;
96     IsosurfaceExtraction::extract (getDistance, PrimAABox (min, max), this->resolution, mesh);
97 
98     State& state = this->self->state ();
99     return state.scene ().newDynamicMesh (state.config (), mesh);
100   }
101 
runReleaseEventToolConvertSketch::Impl102   ToolResponse runReleaseEvent (const ViewPointingEvent& e)
103   {
104     if (e.leftButton ())
105     {
106       SketchMeshIntersection intersection;
107       if (this->self->intersectsScene (e, intersection))
108       {
109         SketchMesh& sMesh = intersection.mesh ();
110 
111         this->self->snapshotAll ();
112 
113         ToolSculptAction::smoothMesh (this->convert (sMesh));
114         this->self->state ().scene ().deleteMesh (sMesh);
115         return ToolResponse::Redraw;
116       }
117     }
118     return ToolResponse::None;
119   }
120 };
121 
122 DELEGATE_TOOL (ToolConvertSketch)
123 DELEGATE_TOOL_RUN_RELEASE_EVENT (ToolConvertSketch)
124