OpenWalnut  1.5.0dev
WMButterfly.cpp
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 // Additional copyright information:
26 // The class WButterflyCalculator partially relies on the Butterfly Subdivision
27 // algorithm.that dates from Denis Zorin, Peter Schroeder, Wim Sweldens, Nira
28 // Dyn, David Levin and John A. Gregory. The original algorithm is depicted in:
29 // http://wwwmath.tau.ac.il/~niradyn/papers/butterfly.pdf
30 // http://mrl.nyu.edu/~dzorin/papers/zorin1996ism.pdf
31 // This work was required especially in the methods calcNewVertex and
32 // getInterpolatedValue.
33 
34 #include <cmath>
35 #include <memory>
36 #include <string>
37 
38 #include <osg/Geometry>
39 
40 #include "WMButterfly.h"
41 #include "WMButterfly.xpm"
42 #include "core/dataHandler/WDataSetScalar.h"
43 #include "core/graphicsEngine/WGEGeodeUtils.h"
44 #include "core/graphicsEngine/WGEManagedGroupNode.h"
45 #include "core/graphicsEngine/callbacks/WGELinearTranslationCallback.h"
46 #include "core/graphicsEngine/shaders/WGEPropertyUniform.h"
47 #include "core/graphicsEngine/shaders/WGEShader.h"
48 #include "core/kernel/WKernel.h"
49 #include "core/kernel/WModuleInputData.h"
50 #include "structure/WVertexFactory.h"
51 
52 
53 // This line is needed by the module loader to actually find your module.
54 W_LOADABLE_MODULE( WMButterfly )
55 
57  WModule(), m_propCondition( new WCondition() )
58 {
59  m_butterfly = new WButterflyFactory();
60  m_butterfly->assignProgressCombiner( m_progress );
61 }
62 
64 {
65 }
66 
67 std::shared_ptr<WModule> WMButterfly::factory() const
68 {
69  return std::shared_ptr<WModule>(new WMButterfly());
70 }
71 
72 const char** WMButterfly::getXPMIcon() const
73 {
74  return WMButterfly_xpm;
75 }
76 
77 const std::string WMButterfly::getName() const
78 {
79  return "Butterfly subdivision";
80 }
81 
82 const std::string WMButterfly::getDescription() const
83 {
84  return "Subdivides triangles in a mesh using the improved butterfly scheme (Zorin et al., 1996).";
85 }
86 
87 /**Plugin connectors
88  * @author schwarzkopf */
90 {
92  "input mesh", "The mesh to display" );
93  m_output = std::shared_ptr<WModuleOutputData<WTriangleMesh> >(
94  new WModuleOutputData<WTriangleMesh>( shared_from_this(),
95  "output mesh",
96  "The loaded mesh." ) );
99 }
100 
101 /**Properties panel
102  * @author schwarzkopf */
104 {
105  // ---> Put the code for your properties here. See "src/modules/template/" for an extensively documented example.
106  m_butterflySettingW = m_properties->addProperty( "Butterfly setting w: ",
107  "It's the general Butterfly Subdivision setting w that affects "
108  "the subdivision. It's usually chosen substantially small. "
109  "The original authors used 0.0.",
110  0.0,
111  m_propCondition );
112  m_butterflySettingW->setMin( -0.125 );
113  m_butterflySettingW->setMax( 0.125 );
114  m_iterations = m_properties->addProperty( "Iterations count: ",
115  "Iteration count that is attempted regarding the maximal triangle count.",
116  1,
117  m_propCondition );
118  m_iterations->setMin( 0 );
119  m_iterations->setMax( 10 );
120  m_maxTriangles10n = m_properties->addProperty( "Max. triangles = 10^: ",
121  "Maximal triangle count as result, scaled by 10^n. "
122  "The Subdivision stops when the triangle count is above it.",
123  6.8,
124  m_propCondition );
125  m_maxTriangles10n->setMin( 2 );
126  m_maxTriangles10n->setMax( 8 );
127  m_maxTriangles = m_properties->addProperty( "Max triangles: ",
128  "Maximal triangle count as result. "
129  "The Subdivision stops when the triangle count is above it.",
130  ( int ) pow( 10, m_maxTriangles10n->get() ) );
131  m_maxTriangles->setPurpose( PV_PURPOSE_INFORMATION );
132  m_cpuThreads = m_properties->addProperty( "CPU threads: ",
133  "Number of CPU cores/threads to use. 1,4x with 2, "
134  "1,7x with 4 threads and 2,2x speed with 8 threads "
135  "(total cycle performance).",
136  8,
137  m_propCondition );
138  m_cpuThreads->setMin( 1 );
139  m_cpuThreads->setMax( 12 );
140  m_minTransformationAngle = m_properties->addProperty( "Min. transform angle: ",
141  "There are no subdivision in lines where the angle transformation "
142  "at the stencil center point would not exceed this value.",
143  0.0,
144  m_propCondition );
145  m_minTransformationAngle->setMin( 0.0 );
146  m_minTransformationAngle->setMax( 90.0 );
147  m_maxTransformationAngle = m_properties->addProperty( "Max. transform angle: ",
148  "There are no subdivision in lines where the angle transformation "
149  "at the stencil center point would exceed this value.",
150  180.0,
151  m_propCondition );
152  m_maxTransformationAngle->setMin( 0.0 );
153  m_maxTransformationAngle->setMax( 180.0 );
154  m_minQuotient = m_properties->addProperty( "Min. lengths quotient: ",
155  "Minimal allowed quotient of the new lines that lie between "
156  "the stencil center points and the new point.",
157  0.0,
158  m_propCondition );
159  m_minQuotient->setMin( 0.0 );
160  m_minQuotient->setMax( 1.0 );
161  m_minAmountOfMax = m_properties->addProperty( "Min. amount of max.: ",
162  "Line length divided by that value must be at least as big "
163  "as the longest line in the stencil in order to subdivide.",
164  0.0,
165  m_propCondition );
166  m_minAmountOfMax->setMin( 0.0 );
167  m_minAmountOfMax->setMax( 1.0 );
168  m_minAmountOfAverage = m_properties->addProperty( "Min. am. of average.: ",
169  "Line length divided by that value must be at least as big "
170  "as the average line in the stencil in order to subdivide.",
171  0.0,
172  m_propCondition );
173  m_minAmountOfAverage->setMin( 0.0 );
174  m_minAmountOfAverage->setMax( 1.0 );
175  m_minSubdividedLineLength = m_properties->addProperty( "Min. div. line length: ",
176  "Lines below that length are not subdivided.",
177  0.0,
178  m_propCondition );
179  m_minSubdividedLineLength->setMin( 0.0 );
180  m_minSubdividedLineLength->setMax( 1.0 );
181  m_minSubdividedLineLengthMultiplierPerIteration = m_properties->addProperty( " Its iteration factor: ",
182  "Amount which multiplies the value above after each iteration. "
183  "As consequence subdivision is don by the order of connection "
184  "length.",
185  1.0,
186  m_propCondition );
189  m_minNeighbourTriangleAngle = m_properties->addProperty( "Minimal triangle angle: ",
190  "Connections that have angles in shared triangles below that "
191  "angle are interpolated by the mixture of linearly and proposed "
192  "subdivision, weighted by the comparison between the smallest "
193  "angle and this limit.",
194  0.0,
195  m_propCondition );
196  m_minNeighbourTriangleAngle->setMin( 0.0 );
197  m_minNeighbourTriangleAngle->setMax( 90.0 );
198  m_maxNeighbourTriangleAngle = m_properties->addProperty( "Maximal triangle angle: ",
199  "A subdivision is marked as invalid if the angle between any "
200  "neighbor triangle line is above that angle.",
201  180.0,
202  m_propCondition );
203  m_maxNeighbourTriangleAngle->setMin( 0.0 );
204  m_maxNeighbourTriangleAngle->setMax( 180.0 );
205  m_maxNeighbourTriangleAngleLengthRatio = m_properties->addProperty( " Its length ratio: ",
206  "If the line length is smaller than the subdividable line "
207  "by this ratio, then it won't be marked as invalid.",
208  0.3,
209  m_propCondition );
212  m_maxAmountOfMaxForVertexJoin = m_properties->addProperty( "min Edge amount for join: ",
213  "Examining all triangles. If any line is smaller than the "
214  "longest multiplied by this value so the points of the small "
215  "line will be joined.",
216  0.0,
217  m_propCondition );
218  m_maxAmountOfMaxForVertexJoin->setMin( 0.0 );
219  m_maxAmountOfMaxForVertexJoin->setMax( 0.6 );
220  m_maxNeighbourTriangleAngleTriangleFlip = m_properties->addProperty( "Flip below angle: ",
221  "If any triangle that connects two vertices has two angles at "
222  "these points that both are below this degree value so the "
223  "triangle orientation is rotated in this square constellation",
224  0.0,
225  m_propCondition );
229 }
230 
232 {
233 }
234 
235 /**Main method which directs the input WTriangleMesh to the Butterfly Subdivision filter
236  * and puts out the result
237  * @author schwarzkopf */
239 {
240  // get notified about data changes
241  m_moduleState.setResetable( true, true );
242  m_moduleState.add( m_input->getDataChangedCondition() );
244 
245  ready();
246 
247  // graphics setup
248  m_rootNode = osg::ref_ptr<WGEManagedGroupNode>( new WGEManagedGroupNode( m_active ) );
249  WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( m_rootNode );
250 
251  // main loop
252  while( !m_shutdownFlag() )
253  {
255 
256  int maxTriangles = ( int ) pow( 10, m_maxTriangles10n->get() );
257  m_maxTriangles->set( maxTriangles );
258 
259  m_butterfly->setButterflySettingW( static_cast<float>( m_butterflySettingW->get() ) );
260  m_butterfly->setIterationsSettings( ( size_t )( m_iterations->get() ),
261  static_cast<float>( m_maxTriangles10n->get() ) );
262  m_butterfly->setCpuThreadCount( ( size_t ) m_cpuThreads->get() );
263 
265  validator->setMinTransformationAngle( static_cast<float>( m_minTransformationAngle->get() ) );
266  validator->setMaxTransformationAngle( static_cast<float>( m_maxTransformationAngle->get() ) );
267  validator->setMinLenghtsQuotient( static_cast<float>( m_minQuotient->get() ) );
268  validator->setMinAmountOfMax( static_cast<float>( m_minAmountOfMax->get() ) );
269  validator->setMinAmountOfAverage( static_cast<float>( m_minAmountOfAverage->get() ) );
270  validator->setMinSubdividedLineLength( static_cast<float>( m_minSubdividedLineLength->get() ) );
272  validator->setMinMeighbourTriangleAngle( static_cast<float>( m_minNeighbourTriangleAngle->get() ) );
273  validator->setMaxNeighbourTriangleAngle( static_cast<float>( m_maxNeighbourTriangleAngle->get() ),
274  static_cast<float>( m_maxNeighbourTriangleAngleLengthRatio->get() ) );
275  validator->setMaxAmountOfMaxForVertexJoin( static_cast<float>( m_maxAmountOfMaxForVertexJoin->get() ) );
277 
278  m_mesh = m_input->getData();
279  if ( m_mesh )
280  {
282 
283  std::shared_ptr< WTriangleMesh > interpolatedMesh = m_butterfly->getSubdividedMesh( m_mesh );
284  m_output->updateData( interpolatedMesh );
285 
287  {
288  usleep( 1000000 ); //Some plugins have problems if old is purged too fast
289 
290  m_oldInterpolatedMesh->~WTriangleMesh();
291  m_oldInterpolatedMesh->~WTransferable();
292  m_oldInterpolatedMesh->~WPrototyped();
293  }
294  m_oldInterpolatedMesh = interpolatedMesh;
295  }
296 
297  // woke up since the module is requested to finish?
298  if( m_shutdownFlag() )
299  break;
300 
301  // save data behind connectors since it might change during processing
302  std::shared_ptr< WTriangleMesh > meshData = m_input->getData();
303 
304  if( !meshData )
305  continue;
306 
307  // ---> Insert code doing the real stuff here
308  }
309 
310  WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( m_rootNode );
311 }
312 
313 float WMButterfly::getMaxLineLength( std::shared_ptr< WTriangleMesh > inputMesh )
314 {
315  float maxLineLength = 0.0f;
316  for ( size_t triID = 0; triID < inputMesh->triangleSize(); triID++ )
317  {
318  size_t id0 = inputMesh->getTriVertId0( triID );
319  size_t id1 = inputMesh->getTriVertId1( triID );
320  size_t id2 = inputMesh->getTriVertId2( triID );
321  osg::Vec3 point0 = inputMesh->getVertex( id0 );
322  osg::Vec3 point1 = inputMesh->getVertex( id1 );
323  osg::Vec3 point2 = inputMesh->getVertex( id2 );
324  float length0 = WVertexFactory::getDistance( point0, point1 );
325  float length1 = WVertexFactory::getDistance( point0, point2 );
326  float length2 = WVertexFactory::getDistance( point2, point1 );
327  if ( length0 > maxLineLength )
328  maxLineLength = length0;
329 
330  if ( length1 > maxLineLength )
331  maxLineLength = length1;
332 
333  if ( length2 > maxLineLength )
334  maxLineLength = length2;
335  }
336  return maxLineLength>0.0f ?maxLineLength :1.0f;
337 }
virtual void wait() const
Wait for the condition.
void setResetable(bool resetable=true, bool autoReset=true)
Sets the resetable flag.
virtual void add(std::shared_ptr< WCondition > condition)
Adds another condition to the set of conditions to wait for.
Class to encapsulate boost::condition_variable_any.
Definition: WCondition.h:42
This class adds some convenience methods to WGEGroupNode.
static WKernel * getRunningKernel()
Returns pointer to the currently running kernel.
Definition: WKernel.cpp:117
std::shared_ptr< WGraphicsEngine > getGraphicsEngine() const
Returns pointer to currently running instance of graphics engine.
Definition: WKernel.cpp:122
OpenWalnut module that subdivides a triangle mesh in more points resulting a smoother surface.
Definition: WMButterfly.h:58
WPropDouble m_maxNeighbourTriangleAngleTriangleFlip
The Minimal allowed angle which fits in both vertices at a subdividable line end.
Definition: WMButterfly.h:254
WPropDouble m_minTransformationAngle
Angle setting which both angles at the subdivided line ends should be at least as big as this value.
Definition: WMButterfly.h:181
WPropDouble m_minAmountOfMax
Factor for multiplying the maximal distance to a neighbour within the Butterfly stencil.
Definition: WMButterfly.h:201
WPropDouble m_minSubdividedLineLengthMultiplierPerIteration
The factor where the minimal subdivided line length is multiplied by in each Subdivision iteration st...
Definition: WMButterfly.h:219
virtual void properties()
Initialize the properties for this module.
virtual ~WMButterfly()
Destroys this module.
Definition: WMButterfly.cpp:63
WPropInt m_cpuThreads
CPU thread count setting for multithreading support.
Definition: WMButterfly.h:174
WPropDouble m_maxNeighbourTriangleAngle
A subdivision is marked as invalid if the angle between any neighbor triangle line is above that angl...
Definition: WMButterfly.h:233
std::shared_ptr< WModuleInputData< WTriangleMesh > > m_input
Input connector for scalar data.
Definition: WMButterfly.h:127
WPropDouble m_maxNeighbourTriangleAngleLengthRatio
This settings extends If the line length is smaller than the subdividable line by this ratio,...
Definition: WMButterfly.h:240
WPropDouble m_maxAmountOfMaxForVertexJoin
The Factor for comparison to the maximal length of a triangle.
Definition: WMButterfly.h:246
std::shared_ptr< WCondition > m_propCondition
Needed for recreating the geometry, incase when resolution changes.
Definition: WMButterfly.h:145
WPropInt m_maxTriangles
Maximal allowed triangle count after Butterfly subdivision.
Definition: WMButterfly.h:169
WPropDouble m_minAmountOfAverage
Factor for multiplying the average distance to a neighbour within the Butterfly stencil.
Definition: WMButterfly.h:207
std::shared_ptr< WTriangleMesh > m_mesh
Triangle mesh which will be assigned to the Butterfly subdivision instance.
Definition: WMButterfly.h:259
std::shared_ptr< WTriangleMesh > m_oldInterpolatedMesh
Holder for the current triangle mesh that grants that there's always a valid data output at the end.
Definition: WMButterfly.h:135
WPropInt m_iterations
The iteration count of the Butterfly subdivision to attempt.
Definition: WMButterfly.h:157
WPropDouble m_minQuotient
Maximum factor which the following lines should differ to show a valid subdivision.
Definition: WMButterfly.h:195
virtual void requirements()
Initialize requirements for this module.
std::shared_ptr< WModuleOutputData< WTriangleMesh > > m_output
Output connector provided by this module.
Definition: WMButterfly.h:128
osg::ref_ptr< WGEManagedGroupNode > m_rootNode
The OSG root node for this module.
Definition: WMButterfly.h:140
virtual const std::string getDescription() const
Gives back a description of this module.
Definition: WMButterfly.cpp:82
virtual const std::string getName() const
Gives back the name of this module.
Definition: WMButterfly.cpp:77
virtual void moduleMain()
Entry point after loading the module.
WMButterfly()
Creates the module for subdividing a triangle mesh using Butterfly subdivision.
Definition: WMButterfly.cpp:56
WPropDouble m_minSubdividedLineLength
The minimal subdividable line length.
Definition: WMButterfly.h:213
float getMaxLineLength(std::shared_ptr< WTriangleMesh > inputMesh)
Returns the biggest length of a neighbour relationship.
virtual const char ** getXPMIcon() const
Get the icon for this module in XPM format.
Definition: WMButterfly.cpp:72
WPropDouble m_maxTriangles10n
Maximal allowed triangle count after Butterfly subdivision.
Definition: WMButterfly.h:163
WPropDouble m_butterflySettingW
The general Butterfly Subdivision setting w that affects the subdivision.
Definition: WMButterfly.h:152
WPropDouble m_maxTransformationAngle
Angle setting which both angles at the subdivided line ends should be not bigger than this value.
Definition: WMButterfly.h:188
virtual void connectors()
Initialize the connectors this module is using.
Definition: WMButterfly.cpp:89
butterfly::WButterflyFactory * m_butterfly
Butterfly subdivision instance.
Definition: WMButterfly.h:264
virtual std::shared_ptr< WModule > factory() const
Due to the prototype design pattern used to build modules, this method returns a new instance of this...
Definition: WMButterfly.cpp:67
WPropDouble m_minNeighbourTriangleAngle
The Minimal allowed angle between two Subdivided line ends.
Definition: WMButterfly.h:227
static PtrType createAndAdd(std::shared_ptr< WModule > module, std::string name="", std::string description="")
Convenience method to create a new instance of this in data connector with proper type and add it to ...
Class offering an instantiate-able data connection between modules.
Class representing a single module of OpenWalnut.
Definition: WModule.h:72
virtual void properties()
Initialize properties in this function.
Definition: WModule.cpp:212
void addConnector(std::shared_ptr< WModuleInputConnector > con)
Adds the specified connector to the list of inputs.
Definition: WModule.cpp:108
std::shared_ptr< WProperties > m_properties
The property object for the module.
Definition: WModule.h:640
void ready()
Call this whenever your module is ready and can react on property changes.
Definition: WModule.cpp:505
WConditionSet m_moduleState
The internal state of the module.
Definition: WModule.h:703
WPropBool m_active
True whenever the module should be active.
Definition: WModule.h:723
virtual void connectors()
Initialize connectors in this function.
Definition: WModule.cpp:208
WBoolFlag m_shutdownFlag
Condition getting fired whenever the thread should quit.
Class that depicts the whole Butterfly subdivision algorithm but nothing more as such.
WSubdivisionValidator * getValidator()
Returns the Butterfly subdivision validator.
void setCpuThreadCount(size_t cpuThreadCount)
Sets the count of CPU threads to use.
std::shared_ptr< WTriangleMesh > getSubdividedMesh(std::shared_ptr< WTriangleMesh > edgedMmesh)
Launch the Butterfly subdivision.
void setButterflySettingW(float butterflySettingW)
Set the general Butterfly Subdivision setting w that affects the subdivision.
void setIterationsSettings(float m_iterations, float m_maxTriangles10n)
Assign main butterfly subdivision iterations settings.
Class that validates the Butterfly subdivision.
void setMinMeighbourTriangleAngle(float minNeighbourTriangleAngle)
Sets the Minimal allowed angle between two Subdivided line ends.
void setMinSubdividedLineLength(float minSubdividedLineLength)
Sets the minimal subdividable line length.
void setMinTransformationAngle(float minTransformationAngle)
Sets up the angle setting which both angles at the subdivided line ends should be at least as big as ...
void setMinAmountOfMax(float minAmountOfMax)
Sets the factor for multiplying the maximal distance to a neighbour within the Butterfly stencil.
void setMinAmountOfAverage(float minAmountOfAverage)
Sets the factor for multiplying the average distance to a neighbour within the Butterfly stencil.
void setMaxNeighbourTriangleAngle(float maxNeighbourTriangleAngle, float maxNeighbourTriangleAngleLengthRatio)
Sets settings of the further feature: A subdivision is marked as invalid if the angle between any nei...
void setMinLenghtsQuotient(float minLenghtsQuotient)
Sets the maximum factor which the following lines should differ to show a valid subdivision.
void setMinSubdividedLineLengthMultiplierPerIteration(float minSubdividedLineLengthMultiplierPerIteration)
Sets the factor where the minimal subdivided line length is multiplied by in each Subdivision iterati...
void setMaxNeighbourTriangleAngleTriangleFlip(float maxNeighbourTriangleAngleTriangleFlip)
Sets the Minimal allowed angle which fits in both vertices at a subdividable line end.
void setMaxTransformationAngle(float maxTransformationAngle)
Sets up the angle setting which both angles at the subdivided line ends should be not bigger than thi...
void setMaxAmountOfMaxForVertexJoin(float maxAmountOfMaxForVertexJoin)
Sets the Factor for comparison to the maximal length of a triangle.