OpenWalnut  1.5.0dev
WButterflyCalculator.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 // This class partially relies on the Butterfly Subdivision algorithm.
27 // that dates from Denis Zorin, Peter Schroeder, Wim Sweldens, Nira Dyn, David
28 // 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 <memory>
35 #include <string>
36 #include <vector>
37 
38 #include "WButterflyCalculator.h"
39 #include "WSubdivisionValidator.h"
40 #include "core/kernel/WKernel.h"
41 
42 
43 namespace butterfly
44 {
45  float WButterflyCalculator::m_w = 0.0f;
47  {{0.75f, 5.0f / 12.0f, -1.0f / 12.0f, -1.0f / 12.0f, 0.0f, 0.0f, 0.0f}, /*Valence=3*///NOLINT
48  {0.875f, 3.0f / 8.0f, -1.0f / 8.0f, 0.0f, -1.0f / 8.0f, 0.0f, 0.0f},/*Valence=4*///NOLINT
49  {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},//NOLINT
50  {0.5f - m_w, 0.0f, 0.0625f + m_w, -0.0625f - m_w, m_w, -0.0625f - m_w, 0.0625f + m_w}};/*Valence=6*///NOLINT
52  float WButterflyCalculator::m_weightRimAtBorder = -1.0f / 16.0f;
53 
55  {
56  m_verts = new WVertexFactory();
57  }
58 
60  {
61  // TODO(schwarzkopf): Auto-generated destructor stub
62  }
63  void WButterflyCalculator::assignInputMesh( std::shared_ptr< WTriangleMesh > inputMesh,
64  WVertexFactory* vertexProperties )
65  {
66  this->m_inputMesh = inputMesh;
67  this->m_verts = vertexProperties;
68  }
69  void WButterflyCalculator::setButterflySettingW( float butterflySettingW )
70  {
71  m_w = butterflySettingW;
72  m_weights[3][0] = 0.5f - m_w;
73  m_weights[3][2] = 0.0625f + m_w;
74  m_weights[3][3] = -0.0625f - m_w;
75  m_weights[3][4] = m_w;
76  m_weights[3][5] = -0.0625f - m_w;
77  m_weights[3][6] = 0.0625f + m_w;
78  }
79 
80  osg::Vec3 WButterflyCalculator::calcNewVertex( size_t vertID1, size_t vertID2 )
81  {
82  int bound1 = m_verts->getProperty( vertID1 )->getBoundClass();
83  int bound2 = m_verts->getProperty( vertID2 )->getBoundClass();
84  int valence1 = m_verts->getProperty( vertID1 )->getValence();
85  int valence2 = m_verts->getProperty( vertID2 )->getValence();
86  if( bound1 == 1 )
87  valence1 += valence1 - 2;
88  if( bound2 == 1 )
89  valence2 += valence2 - 2;
90  Vec3 final = Vec3( 0.0f, 0.0f, 0.0f );
91  if ( bound1 < 2 && bound2 < 2 && bound1 >= 0 && bound2 >= 0 )
92  {
93  if( bound1 != 1 || bound2 != 1 )
94  { //Case 1: two vertices of valence 6
95  if ( valence1 == 6 && valence2 == 6 )
96  {
97  final = m_verts->add( Vec3( 0.0f, 0.0f, 0.0f ),
98  getInterpolatedValue( vertID1, vertID2, false ), 1.0f );
99  final = m_verts->add( final,
100  getInterpolatedValue( vertID2, vertID1, false ), 1.0f );
101  }
102  else if( valence1 != 6 || valence2 != 6 )
103  { //Case 2/3: at least one vertex of valence!=6
104  final = m_verts->add( Vec3( 0.0f, 0.0f, 0.0f ),
105  getInterpolatedValue( vertID1, vertID2, true ), 0.5f );
106  final = m_verts->add( final,
107  getInterpolatedValue( vertID2, vertID1, true ), 0.5f );
108  }
109  }
110  else
111  { //Case 4: >=1 vertex on a bound
112  int start1 = m_verts->getProperty( vertID1 )->getStencilNeighbourIndex( vertID2 );
113  int start2 = m_verts->getProperty( vertID2 )->getStencilNeighbourIndex( vertID1 );
114  size_t boundNeighbour = m_verts->getProperty( vertID1 )->getStencilNeighbourID( valence1 / 2 - start1 );
115  final = m_verts->add( Vec3( 0.0f, 0.0f, 0.0f ), m_inputMesh->getVertex( boundNeighbour ), m_weightRimAtBorder );
116  boundNeighbour = m_verts->getProperty( vertID2 )->getStencilNeighbourID( valence2 / 2 - start2 );
117  final = m_verts->add( final, m_inputMesh->getVertex( boundNeighbour ), m_weightRimAtBorder );
118  final = m_verts->add( final, m_inputMesh->getVertex( vertID1 ), m_weightCenterAtBorder );
119  final = m_verts->add( final, m_inputMesh->getVertex( vertID2 ), m_weightCenterAtBorder );
120  }
121  }
122  else
123  final = calcMean( vertID1, vertID2 );
124 
125  return final;
126  }
127  Vec3 WButterflyCalculator::calcMean( size_t vertID1, size_t vertID2 )
128  {
129  Vec3 vert1 = m_inputMesh->getVertex( vertID1 ),
130  vert2 = m_inputMesh->getVertex( vertID2 );
131  float coordX = ( vert1.x() + vert2.x() ) / 2.0f,
132  coordY = ( vert1.y() + vert2.y() ) / 2.0f,
133  coordZ = ( vert1.z() + vert2.z() ) / 2.0f;
134  return osg::Vec3( coordX , coordY, coordZ );
135  }
136  Vec3 WButterflyCalculator::getInterpolatedValue( size_t stencilCenterVertID,
137  size_t directedNeighbourVertID, bool isIrregular )
138  {
139  WVertexProperty* property = m_verts->getProperty( stencilCenterVertID );
140  int start = property->getStencilNeighbourIndex( directedNeighbourVertID );
141  float valence = property->getValence();
142  int bounds = property->getBoundClass();
143  if ( bounds == 1 )
144  valence += valence - 2;
145 
146  int weightRow = static_cast<int>( valence + 0.3f ) - 3;
147  bool hasCustomWeight = ( valence == 3 || valence == 4 || ( valence == 6 && !isIrregular ) );
148  Vec3 final = m_verts->add( Vec3( 0.0f, 0.0f, 0.0f ), m_inputMesh->getVertex( stencilCenterVertID ),
149  hasCustomWeight ? m_weights[weightRow][0] : m_weights[0][0] );
150 
151  for ( int index = 0; index < valence; index++ )
152  {
153  float neighbour = index - start;
154  if ( neighbour < 0.0f )
155  neighbour = valence + neighbour;
156 
157  bool isBehindBound = ( bounds == 1 && index > valence / 2 );
158  int i_mirrored = isBehindBound ?index-valence/2 :index,
159  weightCol = 1 + static_cast<int>( neighbour + 0.3f );
160  int neighbourID = property->getStencilNeighbourID( i_mirrored );
161  float weight = hasCustomWeight ?m_weights[weightRow][weightCol]
162  :( 0.25f + cos( 2.0f * M_PI * neighbour / valence )
163  + 0.5f * cos( 4.0f * M_PI * neighbour / valence ) ) / valence;
164  Vec3 value = m_inputMesh->getVertex( neighbourID );
165  if ( isBehindBound )
166  { //Case 4: >=1 vertex on a bound
167  value = m_verts->add( m_inputMesh->getVertex( stencilCenterVertID ), value, -1.0f );
168  value = m_verts->add( m_inputMesh->getVertex( stencilCenterVertID ), value, 1.0f );
169  }
170  final = m_verts->add( final, value, weight );
171  }
172  return final;
173  }
174 
175 } /* namespace std */
Object that contains all necessary properties of a vertex necessary for a sufficient analysis.
int getStencilNeighbourIndex(size_t neighbourID)
Returns the Stencil neighbor index of a particular vertex ID.
size_t getStencilNeighbourID(size_t index)
Returns a neighbor ID within the stencil by the index.
size_t getValence()
Returns the Neighbor vertex count of the current vertex.
int getBoundClass()
Returns the bound count class of the stencil's center point.
osg::Vec3 calcMean(size_t vertID1, size_t vertID2)
Calculate a subdivided mit point between two vertices using the mean calculation.
void assignInputMesh(std::shared_ptr< WTriangleMesh > inputMesh, WVertexFactory *vertexProperties)
Assigns the input mesh andd its analyzed data that are required for the butterfly subdivision.
Vec3 getInterpolatedValue(size_t stencilCenterVertID, size_t directedNeighbourVertID, bool isIrregular)
Calculate the coordinates of a stencil half using the Butterfly subdivision algorithm.
WVertexFactory * m_verts
Associated data set used for analyzation of the triangle mesh.
static float m_weightCenterAtBorder
Weight where both stencil centers lie on a border.
std::shared_ptr< WTriangleMesh > m_inputMesh
Base triangle mesh used for calculations.
static float m_weightRimAtBorder
Weight where both stencil centers lie on a border.
void setButterflySettingW(float butterflySettingW)
Set the general Butterfly Subdivision setting w that affects the subdivision.
osg::Vec3 calcNewVertex(size_t vertID1, size_t vertID2)
Calculate the subdivided new vertex between two vertices using the Butterfly Subdivision.
WButterflyCalculator()
Butterfly subdivision tool object creating instance.
virtual ~WButterflyCalculator()
Destroys the Butterfly instance object and its substructures.
static float m_weights[4][7]
Butterfly subdivision Weights for each neighbor which always are applied for valences 3 and 4.
static float m_w
The general Butterfly Subdivision setting w that affects the subdivision.
Class that manages all vertex properties.
WVertexProperty * getProperty(size_t vertexID)
Get properties of a vertex.
static osg::Vec3 add(osg::Vec3 base, osg::Vec3 sum, float factor)
Adding a sum multiplied by a factor to the base number.