TexGen
SectionMeshRectangular.cpp
Go to the documentation of this file.
1/*=============================================================================
2TexGen: Geometric textile modeller.
3Copyright (C) 2006 Martin Sherburn
4
5This program is free software; you can redistribute it and/or
6modify it under the terms of the GNU General Public License
7as published by the Free Software Foundation; either version 2
8of the License, or (at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18=============================================================================*/
19
20#include "PrecompiledHeaders.h"
22
23using namespace TexGen;
24CSectionMeshRectangular::CSectionMeshRectangular(int iNumLayers, bool bTriangleCorners)
25: m_iNumLayers(iNumLayers)
26, m_bTriangleCorners(bTriangleCorners)
27{
28 if (iNumLayers != -1 && iNumLayers % 2 != 0)
29 {
30 assert(false);
31 TGERROR("Warning: Rectangular mesh specified with an odd number of layers: " << iNumLayers);
32 }
33}
34
36{
37}
38
40{
41 Element.Attribute("NumLayers", &m_iNumLayers);
42 m_bTriangleCorners = valueify<bool>(Element.Attribute("TriangleCorners"));
43}
44
45void CSectionMeshRectangular::PopulateTiXmlElement(TiXmlElement &Element, OUTPUT_TYPE OutputType) const
46{
47 CSectionMesh::PopulateTiXmlElement(Element, OutputType);
48 Element.SetAttribute("NumLayers", m_iNumLayers);
49 Element.SetAttribute("TriangleCorners", stringify(m_bTriangleCorners));
50}
51
52bool CSectionMeshRectangular::CreateMesh(const vector<XY> &Section) const
53{
54 int iNumLayers = m_iNumLayers;
55 if (m_iNumLayers == -1)
56 iNumLayers = CalculateNumberofLayers(Section);
57 else if (m_iNumLayers == 1)
58 return CreateSingleLayerMesh(Section);
59 if (iNumLayers % 2 != 0)
60 {
61 assert(false);
62 TGERROR("Unable to create section mesh, the number of layers is odd: " << iNumLayers);
63 return false;
64 }
65 if (Section.size() % 2 != 0)
66 {
67 assert(false);
68 TGERROR("Unable to create section mesh, the number of sections points specified is odd: " << Section.size());
69 return false;
70 }
71 int iNumColumns = Section.size()/2-iNumLayers;
73 iNumColumns += 2;
74 if (iNumColumns < 1)
75 {
76 assert(false);
77 TGERROR("Unable to create section mesh, the number of columns is less than 1: " << iNumColumns);
78 return false;
79 }
80 int i, j;
81 int iPointIndex, iNumPoints = (int)Section.size();
82
83 vector<XY> Left;
84 vector<XY> Right;
85 vector<XY> Top;
86 vector<XY> Bottom;
87
89 iNumColumns -= 2;
90 for (i=0; i<iNumLayers+1; ++i) // Assemble right and left perimeter points
91 {
92 if (m_bTriangleCorners && (i == 0 || i == iNumLayers))
93 {
94 // Insert dummy points at the corners
95 Right.push_back(XY());
96 Left.push_back(XY());
97 continue;
98 }
99 if (i < iNumLayers/2)
100 iPointIndex = iNumPoints-iNumLayers/2+i;
101 else
102 iPointIndex = i-iNumLayers/2;
103 Right.push_back(Section[iPointIndex]);
104
105 iPointIndex = 3*(iNumLayers/2)+iNumColumns-i;
106 Left.push_back(Section[iPointIndex]);
107 }
109 iNumColumns += 2;
110
112 iNumLayers -= 2;
113 for (i=0; i<iNumColumns+1; ++i) // Assemble top and bottom perimeter points
114 {
115 if (m_bTriangleCorners && (i == 0 || i == iNumColumns))
116 {
117 // Insert dummy points at the corners
118 Top.push_back(XY());
119 Bottom.push_back(XY());
120 continue;
121 }
122 iPointIndex = iNumLayers/2+iNumColumns-i;
123 Top.push_back(Section[iPointIndex]);
124
125 iPointIndex = 3*(iNumLayers/2)+iNumColumns+i;
126 Bottom.push_back(Section[iPointIndex]);
127 }
129 iNumLayers += 2;
130
131 m_Mesh.Clear();
132 m_Mesh.SetNumNodes((iNumLayers+1)*(iNumColumns+1));
133 double u, v;
134 double w1, w2;
135 double l1, l2;
136 double d1, d2;
137 XY P, P1, P2;
138 for (i=0; i<iNumLayers+1; ++i)
139 {
140 u = double(i) / double(iNumLayers);
141 for (j=0; j<iNumColumns+1; ++j)
142 {
143 v = double(j) / double(iNumColumns);
144 P1 = Left[i] + (Right[i] - Left[i])*v; // MS thesis equ 2.56
145 P2 = Bottom[j] + (Top[j] - Bottom[j])*u; // equ 2.57
146 d1 = 0.5-abs(v-0.5); // 2nd half of equ 2.58 corrected to use v not u as in thesis
147 d2 = 0.5-abs(u-0.5); // 2nd half of equ 2.59 corrected to use u not v
148 l1 = GetLength(Left[i], Right[i]);
149 l2 = GetLength(Bottom[j], Top[j]);
150 if (l1)
151 d1 *= l1; // equ 2.58
152 if (l2)
153 d2 *= l2; // equ 2.59
154 if (d1 + d2 == 0) // Avoid division by 0
155 {
156 w1 = w2 = 0.5;
157 }
158 else
159 {
160 w1 = d2 / (d1 + d2); // equ 2.60
161 w2 = d1 / (d1 + d2); // equ 2.61
162 }
163 P = P1 * w1 + P2 * w2; // equ 2.62
164 m_Mesh.SetNode(j+i*(iNumColumns+1), XYZ(P.x, P.y, 0));
165 }
166 }
167 for (i=0; i<iNumLayers; ++i)
168 {
169 for (j=0; j<iNumColumns; ++j)
170 {
172 {
173 if ((i==0 || i==iNumLayers-1) && (j==0 || j==iNumColumns-1))
174 {
175 vector<int> Indices;
176 if (i!=0 || j!=0)
177 Indices.push_back((j+0)+(i+0)*(iNumColumns+1));
178 if (i!=0 || j!=iNumColumns-1)
179 Indices.push_back((j+1)+(i+0)*(iNumColumns+1));
180 if (i!=iNumLayers-1 || j!=iNumColumns-1)
181 Indices.push_back((j+1)+(i+1)*(iNumColumns+1));
182 if (i!=iNumLayers-1 || j!=0)
183 Indices.push_back((j+0)+(i+1)*(iNumColumns+1));
184 m_Mesh.AddElement(CMesh::TRI, Indices);
185 continue;
186 }
187 }
188 m_Mesh.GetIndices(CMesh::QUAD).push_back((j+0)+(i+0)*(iNumColumns+1));
189 m_Mesh.GetIndices(CMesh::QUAD).push_back((j+1)+(i+0)*(iNumColumns+1));
190 m_Mesh.GetIndices(CMesh::QUAD).push_back((j+1)+(i+1)*(iNumColumns+1));
191 m_Mesh.GetIndices(CMesh::QUAD).push_back((j+0)+(i+1)*(iNumColumns+1));
192 }
193 }
194 bool bSurfaceNodes = true; // Add this to class later
195 if ( bSurfaceNodes )
196 {
197 vector<int> Indices;
198 for ( j = 1; j < iNumColumns; ++j )
199 {
200 Indices.push_back(j); // Nodes along top
201 }
202 for ( i = 1; i < iNumLayers; ++i )
203 {
204 Indices.push_back( iNumColumns + i * (iNumColumns+1) ); // Nodes down right side
205 }
206 for ( j = iNumColumns-1; j > 0; --j )
207 {
208 Indices.push_back( j + iNumLayers * (iNumColumns+1) ); // Nodes across bottom (right to left)
209 }
210 for ( i = iNumLayers-1; i > 0; --i )
211 {
212 Indices.push_back( i * (iNumColumns+1) ); // Nodes up left side
213 }
214 Indices.push_back( Indices[0] );
216 }
217
219 {
220 // Remove the four corner dummy nodes...
221 int iRemoved = m_Mesh.RemoveUnreferencedNodes();
222 assert(iRemoved == 4);
223 }
224
225 return true;
226}
227
228int CSectionMeshRectangular::CalculateNumberofLayers(const vector<XY> &Section) const
229{
230 // Section may either be rotated section or not start from point on x axis
231 // in which case the points need rotating back otherwise test for number of layers is invalid
232 XY p1, p2, dp;
233 p1 = Section[0];
234 p2 = Section[Section.size()/2];
235 dp = p1 - p2;
236 double dAngle = atan2( dp.y, dp.x );
237
238 vector<XY> RotatedSection;
239 for ( int i = 1; i <= (int)Section.size()/4+1; ++i )
240 {
241 XY RotPoint;
242 RotPoint.x = Section[i].x*cos(dAngle) + Section[i].y*sin(dAngle);
243 RotPoint.y = Section[i].y*cos(dAngle) - Section[i].x*sin(dAngle);
244 RotatedSection.push_back(RotPoint);
245 }
246
247 // Assuming the section is symmetric about all 4 quadrants
248 // 25-9-12 Can't assume this. Both hybrid and polygon sections may result in non-symmetrical sections
249 int i;
250 XY P1, P2, DP;
251 vector<XY>::iterator itRotatedSection;
252 //for (i=1; i<=(int)RotatedSection.size()/4; ++i)
253 for ( i = 0; i < (int)RotatedSection.size()-1; ++i )
254 {
255 P1 = RotatedSection[i];
256 P2 = RotatedSection[i+1];
257 DP = P2 - P1;
258 if (abs(DP.x) > abs(DP.y))
259 {
260 return (i+1)*2; // +1 because RotatedSection starts at 2nd point in Section
261 }
262 }
263 return i*2;
264 // Should never reach this point
265 //return 0;
266}
267
268bool CSectionMeshRectangular::CreateSingleLayerMesh(const vector<XY> &Section) const
269{
270 if (Section.size() % 2 != 0)
271 {
272 assert(false);
273 TGERROR("Unable to create section mesh, the number of sections points specified is odd: " << Section.size());
274 return false;
275 }
276
277 int iNumColumns = Section.size()/2;
278
279 m_Mesh.Clear();
280 int i, j;
281 for (i=0; i<(int)Section.size(); ++i)
282 {
283 XY pt = Section[i];
284 m_Mesh.AddNode(XYZ(pt.x, pt.y, 0));
285 }
286
287 // Build up a single row of elements, two triangles at either end and rectangles in the middle
288 for (j=0; j<iNumColumns; ++j)
289 {
290 if (j==0)
291 {
292 // Triangle at the right edges
293 vector<int> Indices;
294 Indices.push_back(0);
295 Indices.push_back(1);
296 Indices.push_back(Section.size()-1);
297 m_Mesh.AddElement(CMesh::TRI, Indices);
298 }
299 else if (j==iNumColumns-1)
300 {
301 // Triangle at the left edge
302 vector<int> Indices;
303 Indices.push_back(iNumColumns-1);
304 Indices.push_back(iNumColumns);
305 Indices.push_back(iNumColumns+1);
306 m_Mesh.AddElement(CMesh::TRI, Indices);
307 }
308 else
309 {
310 // Rectangles in the middle section
311 vector<int> Indices;
312 Indices.push_back(j);
313 Indices.push_back(j+1);
314 Indices.push_back(Section.size()-j-1);
315 Indices.push_back(Section.size()-j);
316 m_Mesh.AddElement(CMesh::QUAD, Indices);
317 }
318 }
319
320 bool bSurfaceNodes = true; // Add this to class later
321 if ( bSurfaceNodes )
322 {
323 vector<int> Indices;
324 for ( j = 0; j < (int)Section.size(); ++j )
325 {
326 Indices.push_back(j);
327 }
328 Indices.push_back(Indices[0]);
330 }
331
332 return true;
333}
334
336{
337 m_iNumLayers = iNum;
338}
339
340
341
342
#define TGERROR(MESSAGE)
Macros used to report the file name and line number to the TexGenError and TexGenLog functions.
Definition: Logger.h:29
bool AddElement(ELEMENT_TYPE Type, const vector< int > &Indices)
Add an element to the mesh of given type with node number checking.
Definition: Mesh.cpp:2565
const int AddNode(XYZ Node)
Append a node to the list of nodes, the integer returns the index of the node
Definition: Mesh.cpp:2624
int RemoveUnreferencedNodes()
Remove nodes that are not referenced by any elements.
Definition: Mesh.cpp:687
const list< int > & GetIndices(ELEMENT_TYPE ElemType) const
Get the element indices of a given element type.
Definition: Mesh.cpp:2671
@ POLYGON
Definition: Mesh.h:76
void SetNode(int iIndex, XYZ Node)
Set the node at given index.
Definition: Mesh.cpp:2630
void SetNumNodes(int NumNodes)
Resize the vector size.
Definition: Mesh.cpp:2666
void Clear()
Empty mesh nodes and indices.
Definition: Mesh.cpp:1448
CMesh m_Mesh
Used to cache the result of the previous mesh for efficiency.
Definition: SectionMesh.h:68
virtual void PopulateTiXmlElement(TiXmlElement &Element, OUTPUT_TYPE OutputType) const
Used for saving data to XML.
Definition: SectionMesh.cpp:44
bool CreateSingleLayerMesh(const vector< XY > &Section) const
bool CreateMesh(const vector< XY > &Section) const
Create a mesh out of given list of points representing the edge of the section.
void PopulateTiXmlElement(TiXmlElement &Element, OUTPUT_TYPE OutputType) const
Used for saving data to XML.
CSectionMeshRectangular(int iNumLayers=-1, bool bTriangleCorners=true)
int CalculateNumberofLayers(const vector< XY > &Section) const
Namespace containing a series of customised math operations not found in the standard c++ library.
OUTPUT_TYPE
Definition: Misc.h:105
double GetLength(const XYZ &Point1, const XYZ &Point2)
Get the length between two points.
Definition: mymath.h:540
std::string stringify(const T &x, int iPrecision=12, bool bScientific=true)
Function to convert a value (e.g. int, double, etc...) to a string.
Definition: Misc.h:50
Struct for representing points in 2D space.
Definition: mymath.h:103
double x
Definition: mymath.h:104
double y
Definition: mymath.h:104
Struct for representing points in 3D space.
Definition: mymath.h:56