1/*
2Open Asset Import Library (assimp)
3----------------------------------------------------------------------
4
5Copyright (c) 2006-2017, assimp team
6
7All rights reserved.
8
9Redistribution and use of this software in source and binary forms,
10with or without modification, are permitted provided that the
11following conditions are met:
12
13* Redistributions of source code must retain the above
14copyright notice, this list of conditions and the
15following disclaimer.
16
17* Redistributions in binary form must reproduce the above
18copyright notice, this list of conditions and the
19following disclaimer in the documentation and/or other
20materials provided with the distribution.
21
22* Neither the name of the assimp team, nor the names of its
23contributors may be used to endorse or promote products
24derived from this software without specific prior
25written permission of the assimp team.
26
27THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
39----------------------------------------------------------------------
40*/
41/// \file X3DImporter_Geometry2D.cpp
42/// \brief Parsing data from nodes of "Geometry2D" set of X3D.
43/// \date 2015-2016
44/// \author smal.root@gmail.com
45
46#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
47
48#include "X3DImporter.hpp"
49#include "X3DImporter_Node.hpp"
50#include "X3DImporter_Macro.hpp"
51
52namespace Assimp
53{
54
55// <Arc2D
56// DEF="" ID
57// USE="" IDREF
58// endAngle="1.570796" SFFloat [initializeOnly]
59// radius="1" SFFloat [initializeOnly]
60// startAngle="0" SFFloat [initializeOnly]
61// />
62// The Arc2D node specifies a linear circular arc whose center is at (0,0) and whose angles are measured starting at the positive x-axis and sweeping
63// towards the positive y-axis. The radius field specifies the radius of the circle of which the arc is a portion. The arc extends from the startAngle
64// counterclockwise to the endAngle. The values of startAngle and endAngle shall be in the range [-2pi, 2pi] radians (or the equivalent if a different
65// angle base unit has been specified). If startAngle and endAngle have the same value, a circle is specified.
66void X3DImporter::ParseNode_Geometry2D_Arc2D()
67{
68 std::string def, use;
69 float endAngle = AI_MATH_HALF_PI_F;
70 float radius = 1;
71 float startAngle = 0;
72 CX3DImporter_NodeElement* ne( nullptr );
73
74 MACRO_ATTRREAD_LOOPBEG;
75 MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
76 MACRO_ATTRREAD_CHECK_RET("endAngle", endAngle, XML_ReadNode_GetAttrVal_AsFloat);
77 MACRO_ATTRREAD_CHECK_RET("radius", radius, XML_ReadNode_GetAttrVal_AsFloat);
78 MACRO_ATTRREAD_CHECK_RET("startAngle", startAngle, XML_ReadNode_GetAttrVal_AsFloat);
79 MACRO_ATTRREAD_LOOPEND;
80
81 // if "USE" defined then find already defined element.
82 if(!use.empty())
83 {
84 MACRO_USE_CHECKANDAPPLY(def, use, ENET_Arc2D, ne);
85 }
86 else
87 {
88 // create and if needed - define new geometry object.
89 ne = new CX3DImporter_NodeElement_Geometry2D(CX3DImporter_NodeElement::ENET_Arc2D, NodeElement_Cur);
90 if(!def.empty()) ne->ID = def;
91
92 // create point list of geometry object and convert it to line set.
93 std::list<aiVector3D> tlist;
94
95 GeometryHelper_Make_Arc2D(startAngle, endAngle, radius, 10, tlist);///TODO: IME - AI_CONFIG for NumSeg
96 GeometryHelper_Extend_PointToLine(tlist, ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices);
97 ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = 2;
98 // check for X3DMetadataObject childs.
99 if(!mReader->isEmptyElement())
100 ParseNode_Metadata(ne, "Arc2D");
101 else
102 NodeElement_Cur->Child.push_back(ne);// add made object as child to current element
103
104 NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
105 }// if(!use.empty()) else
106}
107
108// <ArcClose2D
109// DEF="" ID
110// USE="" IDREF
111// closureType="PIE" SFString [initializeOnly], {"PIE", "CHORD"}
112// endAngle="1.570796" SFFloat [initializeOnly]
113// radius="1" SFFloat [initializeOnly]
114// solid="false" SFBool [initializeOnly]
115// startAngle="0" SFFloat [initializeOnly]
116// />
117// The ArcClose node specifies a portion of a circle whose center is at (0,0) and whose angles are measured starting at the positive x-axis and sweeping
118// towards the positive y-axis. The end points of the arc specified are connected as defined by the closureType field. The radius field specifies the radius
119// of the circle of which the arc is a portion. The arc extends from the startAngle counterclockwise to the endAngle. The value of radius shall be greater
120// than zero. The values of startAngle and endAngle shall be in the range [-2pi, 2pi] radians (or the equivalent if a different default angle base unit has
121// been specified). If startAngle and endAngle have the same value, a circle is specified and closureType is ignored. If the absolute difference between
122// startAngle and endAngle is greater than or equal to 2pi, a complete circle is produced with no chord or radial line(s) drawn from the center.
123// A closureType of "PIE" connects the end point to the start point by defining two straight line segments first from the end point to the center and then
124// the center to the start point. A closureType of "CHORD" connects the end point to the start point by defining a straight line segment from the end point
125// to the start point. Textures are applied individually to each face of the ArcClose2D. On the front (+Z) and back (-Z) faces of the ArcClose2D, when
126// viewed from the +Z-axis, the texture is mapped onto each face with the same orientation as if the image were displayed normally in 2D.
127void X3DImporter::ParseNode_Geometry2D_ArcClose2D()
128{
129 std::string def, use;
130 std::string closureType("PIE");
131 float endAngle = AI_MATH_HALF_PI_F;
132 float radius = 1;
133 bool solid = false;
134 float startAngle = 0;
135 CX3DImporter_NodeElement* ne( nullptr );
136
137 MACRO_ATTRREAD_LOOPBEG;
138 MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
139 MACRO_ATTRREAD_CHECK_RET("closureType", closureType, mReader->getAttributeValue);
140 MACRO_ATTRREAD_CHECK_RET("endAngle", endAngle, XML_ReadNode_GetAttrVal_AsFloat);
141 MACRO_ATTRREAD_CHECK_RET("radius", radius, XML_ReadNode_GetAttrVal_AsFloat);
142 MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool);
143 MACRO_ATTRREAD_CHECK_RET("startAngle", startAngle, XML_ReadNode_GetAttrVal_AsFloat);
144 MACRO_ATTRREAD_LOOPEND;
145
146 // if "USE" defined then find already defined element.
147 if(!use.empty())
148 {
149 MACRO_USE_CHECKANDAPPLY(def, use, ENET_ArcClose2D, ne);
150 }
151 else
152 {
153 // create and if needed - define new geometry object.
154 ne = new CX3DImporter_NodeElement_Geometry2D(CX3DImporter_NodeElement::ENET_ArcClose2D, NodeElement_Cur);
155 if(!def.empty()) ne->ID = def;
156
157 ((CX3DImporter_NodeElement_Geometry2D*)ne)->Solid = solid;
158 // create point list of geometry object.
159 GeometryHelper_Make_Arc2D(startAngle, endAngle, radius, 10, ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices);///TODO: IME - AI_CONFIG for NumSeg
160 // add chord or two radiuses only if not a circle was defined
161 if(!((std::fabs(endAngle - startAngle) >= AI_MATH_TWO_PI_F) || (endAngle == startAngle)))
162 {
163 std::list<aiVector3D>& vlist = ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices;// just short alias.
164
165 if((closureType == "PIE") || (closureType == "\"PIE\""))
166 vlist.push_back(aiVector3D(0, 0, 0));// center point - first radial line
167 else if((closureType != "CHORD") && (closureType != "\"CHORD\""))
168 Throw_IncorrectAttrValue("closureType");
169
170 vlist.push_back(*vlist.begin());// arc first point - chord from first to last point of arc(if CHORD) or second radial line(if PIE).
171 }
172
173 ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices.size();
174 // check for X3DMetadataObject childs.
175 if(!mReader->isEmptyElement())
176 ParseNode_Metadata(ne, "ArcClose2D");
177 else
178 NodeElement_Cur->Child.push_back(ne);// add made object as child to current element
179
180 NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
181 }// if(!use.empty()) else
182}
183
184// <Circle2D
185// DEF="" ID
186// USE="" IDREF
187// radius="1" SFFloat [initializeOnly]
188// />
189void X3DImporter::ParseNode_Geometry2D_Circle2D()
190{
191 std::string def, use;
192 float radius = 1;
193 CX3DImporter_NodeElement* ne( nullptr );
194
195 MACRO_ATTRREAD_LOOPBEG;
196 MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
197 MACRO_ATTRREAD_CHECK_RET("radius", radius, XML_ReadNode_GetAttrVal_AsFloat);
198 MACRO_ATTRREAD_LOOPEND;
199
200 // if "USE" defined then find already defined element.
201 if(!use.empty())
202 {
203 MACRO_USE_CHECKANDAPPLY(def, use, ENET_Circle2D, ne);
204 }
205 else
206 {
207 // create and if needed - define new geometry object.
208 ne = new CX3DImporter_NodeElement_Geometry2D(CX3DImporter_NodeElement::ENET_Circle2D, NodeElement_Cur);
209 if(!def.empty()) ne->ID = def;
210
211 // create point list of geometry object and convert it to line set.
212 std::list<aiVector3D> tlist;
213
214 GeometryHelper_Make_Arc2D(0, 0, radius, 10, tlist);///TODO: IME - AI_CONFIG for NumSeg
215 GeometryHelper_Extend_PointToLine(tlist, ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices);
216 ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = 2;
217 // check for X3DMetadataObject childs.
218 if(!mReader->isEmptyElement())
219 ParseNode_Metadata(ne, "Circle2D");
220 else
221 NodeElement_Cur->Child.push_back(ne);// add made object as child to current element
222
223 NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
224 }// if(!use.empty()) else
225}
226
227// <Disk2D
228// DEF="" ID
229// USE="" IDREF
230// innerRadius="0" SFFloat [initializeOnly]
231// outerRadius="1" SFFloat [initializeOnly]
232// solid="false" SFBool [initializeOnly]
233// />
234// The Disk2D node specifies a circular disk which is centred at (0, 0) in the local coordinate system. The outerRadius field specifies the radius of the
235// outer dimension of the Disk2D. The innerRadius field specifies the inner dimension of the Disk2D. The value of outerRadius shall be greater than zero.
236// The value of innerRadius shall be greater than or equal to zero and less than or equal to outerRadius. If innerRadius is zero, the Disk2D is completely
237// filled. Otherwise, the area within the innerRadius forms a hole in the Disk2D. If innerRadius is equal to outerRadius, a solid circular line shall
238// be drawn using the current line properties. Textures are applied individually to each face of the Disk2D. On the front (+Z) and back (-Z) faces of
239// the Disk2D, when viewed from the +Z-axis, the texture is mapped onto each face with the same orientation as if the image were displayed normally in 2D.
240void X3DImporter::ParseNode_Geometry2D_Disk2D()
241{
242 std::string def, use;
243 float innerRadius = 0;
244 float outerRadius = 1;
245 bool solid = false;
246 CX3DImporter_NodeElement* ne( nullptr );
247
248 MACRO_ATTRREAD_LOOPBEG;
249 MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
250 MACRO_ATTRREAD_CHECK_RET("innerRadius", innerRadius, XML_ReadNode_GetAttrVal_AsFloat);
251 MACRO_ATTRREAD_CHECK_RET("outerRadius", outerRadius, XML_ReadNode_GetAttrVal_AsFloat);
252 MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool);
253 MACRO_ATTRREAD_LOOPEND;
254
255 // if "USE" defined then find already defined element.
256 if(!use.empty())
257 {
258 MACRO_USE_CHECKANDAPPLY(def, use, ENET_Disk2D, ne);
259 }
260 else
261 {
262 std::list<aiVector3D> tlist_o, tlist_i;
263
264 if(innerRadius > outerRadius) Throw_IncorrectAttrValue("innerRadius");
265
266 // create and if needed - define new geometry object.
267 ne = new CX3DImporter_NodeElement_Geometry2D(CX3DImporter_NodeElement::ENET_Disk2D, NodeElement_Cur);
268 if(!def.empty()) ne->ID = def;
269
270 // create point list of geometry object.
271 ///TODO: IME - AI_CONFIG for NumSeg
272 GeometryHelper_Make_Arc2D(0, 0, outerRadius, 10, tlist_o);// outer circle
273 if(innerRadius == 0.0f)
274 {// make filled disk
275 // in tlist_o we already have points of circle. just copy it and sign as polygon.
276 ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices = tlist_o;
277 ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = tlist_o.size();
278 }
279 else if(innerRadius == outerRadius)
280 {// make circle
281 // in tlist_o we already have points of circle. convert it to line set.
282 GeometryHelper_Extend_PointToLine(tlist_o, ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices);
283 ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = 2;
284 }
285 else
286 {// make disk
287 std::list<aiVector3D>& vlist = ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices;// just short alias.
288
289 GeometryHelper_Make_Arc2D(0, 0, innerRadius, 10, tlist_i);// inner circle
290 //
291 // create quad list from two point lists
292 //
293 if(tlist_i.size() < 2) throw DeadlyImportError("Disk2D. Not enough points for creating quad list.");// tlist_i and tlist_o has equal size.
294
295 // add all quads except last
296 for(std::list<aiVector3D>::iterator it_i = tlist_i.begin(), it_o = tlist_o.begin(); it_i != tlist_i.end();)
297 {
298 // do not forget - CCW direction
299 vlist.push_back(*it_i++);// 1st point
300 vlist.push_back(*it_o++);// 2nd point
301 vlist.push_back(*it_o);// 3rd point
302 vlist.push_back(*it_i);// 4th point
303 }
304
305 // add last quad
306 vlist.push_back(*tlist_i.end());// 1st point
307 vlist.push_back(*tlist_o.end());// 2nd point
308 vlist.push_back(*tlist_o.begin());// 3rd point
309 vlist.push_back(*tlist_o.begin());// 4th point
310
311 ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = 4;
312 }
313
314 ((CX3DImporter_NodeElement_Geometry2D*)ne)->Solid = solid;
315 // check for X3DMetadataObject childs.
316 if(!mReader->isEmptyElement())
317 ParseNode_Metadata(ne, "Disk2D");
318 else
319 NodeElement_Cur->Child.push_back(ne);// add made object as child to current element
320
321 NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
322 }// if(!use.empty()) else
323}
324
325// <Polyline2D
326// DEF="" ID
327// USE="" IDREF
328// lineSegments="" MFVec2F [intializeOnly]
329// />
330void X3DImporter::ParseNode_Geometry2D_Polyline2D()
331{
332 std::string def, use;
333 std::list<aiVector2D> lineSegments;
334 CX3DImporter_NodeElement* ne( nullptr );
335
336 MACRO_ATTRREAD_LOOPBEG;
337 MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
338 MACRO_ATTRREAD_CHECK_REF("lineSegments", lineSegments, XML_ReadNode_GetAttrVal_AsListVec2f);
339 MACRO_ATTRREAD_LOOPEND;
340
341 // if "USE" defined then find already defined element.
342 if(!use.empty())
343 {
344 MACRO_USE_CHECKANDAPPLY(def, use, ENET_Polyline2D, ne);
345 }
346 else
347 {
348 // create and if needed - define new geometry object.
349 ne = new CX3DImporter_NodeElement_Geometry2D(CX3DImporter_NodeElement::ENET_Polyline2D, NodeElement_Cur);
350 if(!def.empty()) ne->ID = def;
351
352 //
353 // convert read point list of geometry object to line set.
354 //
355 std::list<aiVector3D> tlist;
356
357 // convert vec2 to vec3
358 for(std::list<aiVector2D>::iterator it2 = lineSegments.begin(); it2 != lineSegments.end(); it2++) tlist.push_back(aiVector3D(it2->x, it2->y, 0));
359
360 // convert point set to line set
361 GeometryHelper_Extend_PointToLine(tlist, ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices);
362 ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = 2;
363 // check for X3DMetadataObject childs.
364 if(!mReader->isEmptyElement())
365 ParseNode_Metadata(ne, "Polyline2D");
366 else
367 NodeElement_Cur->Child.push_back(ne);// add made object as child to current element
368
369 NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
370 }// if(!use.empty()) else
371}
372
373// <Polypoint2D
374// DEF="" ID
375// USE="" IDREF
376// point="" MFVec2F [inputOutput]
377// />
378void X3DImporter::ParseNode_Geometry2D_Polypoint2D()
379{
380 std::string def, use;
381 std::list<aiVector2D> point;
382 CX3DImporter_NodeElement* ne( nullptr );
383
384 MACRO_ATTRREAD_LOOPBEG;
385 MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
386 MACRO_ATTRREAD_CHECK_REF("point", point, XML_ReadNode_GetAttrVal_AsListVec2f);
387 MACRO_ATTRREAD_LOOPEND;
388
389 // if "USE" defined then find already defined element.
390 if(!use.empty())
391 {
392 MACRO_USE_CHECKANDAPPLY(def, use, ENET_Polypoint2D, ne);
393 }
394 else
395 {
396 // create and if needed - define new geometry object.
397 ne = new CX3DImporter_NodeElement_Geometry2D(CX3DImporter_NodeElement::ENET_Polypoint2D, NodeElement_Cur);
398 if(!def.empty()) ne->ID = def;
399
400 // convert vec2 to vec3
401 for(std::list<aiVector2D>::iterator it2 = point.begin(); it2 != point.end(); it2++)
402 {
403 ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices.push_back(aiVector3D(it2->x, it2->y, 0));
404 }
405
406 ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = 1;
407 // check for X3DMetadataObject childs.
408 if(!mReader->isEmptyElement())
409 ParseNode_Metadata(ne, "Polypoint2D");
410 else
411 NodeElement_Cur->Child.push_back(ne);// add made object as child to current element
412
413 NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
414 }// if(!use.empty()) else
415}
416
417// <Rectangle2D
418// DEF="" ID
419// USE="" IDREF
420// size="2 2" SFVec2f [initializeOnly]
421// solid="false" SFBool [initializeOnly]
422// />
423void X3DImporter::ParseNode_Geometry2D_Rectangle2D()
424{
425 std::string def, use;
426 aiVector2D size(2, 2);
427 bool solid = false;
428 CX3DImporter_NodeElement* ne( nullptr );
429
430 MACRO_ATTRREAD_LOOPBEG;
431 MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
432 MACRO_ATTRREAD_CHECK_REF("size", size, XML_ReadNode_GetAttrVal_AsVec2f);
433 MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool);
434 MACRO_ATTRREAD_LOOPEND;
435
436 // if "USE" defined then find already defined element.
437 if(!use.empty())
438 {
439 MACRO_USE_CHECKANDAPPLY(def, use, ENET_Rectangle2D, ne);
440 }
441 else
442 {
443 // create and if needed - define new geometry object.
444 ne = new CX3DImporter_NodeElement_Geometry2D(CX3DImporter_NodeElement::ENET_Rectangle2D, NodeElement_Cur);
445 if(!def.empty()) ne->ID = def;
446
447 float x1 = -size.x / 2.0f;
448 float x2 = size.x / 2.0f;
449 float y1 = -size.y / 2.0f;
450 float y2 = size.y / 2.0f;
451 std::list<aiVector3D>& vlist = ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices;// just short alias.
452
453 vlist.push_back(aiVector3D(x2, y1, 0));// 1st point
454 vlist.push_back(aiVector3D(x2, y2, 0));// 2nd point
455 vlist.push_back(aiVector3D(x1, y2, 0));// 3rd point
456 vlist.push_back(aiVector3D(x1, y1, 0));// 4th point
457 ((CX3DImporter_NodeElement_Geometry2D*)ne)->Solid = solid;
458 ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = 4;
459 // check for X3DMetadataObject childs.
460 if(!mReader->isEmptyElement())
461 ParseNode_Metadata(ne, "Rectangle2D");
462 else
463 NodeElement_Cur->Child.push_back(ne);// add made object as child to current element
464
465 NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
466 }// if(!use.empty()) else
467}
468
469// <TriangleSet2D
470// DEF="" ID
471// USE="" IDREF
472// solid="false" SFBool [initializeOnly]
473// vertices="" MFVec2F [inputOutput]
474// />
475void X3DImporter::ParseNode_Geometry2D_TriangleSet2D()
476{
477 std::string def, use;
478 bool solid = false;
479 std::list<aiVector2D> vertices;
480 CX3DImporter_NodeElement* ne( nullptr );
481
482 MACRO_ATTRREAD_LOOPBEG;
483 MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
484 MACRO_ATTRREAD_CHECK_REF("vertices", vertices, XML_ReadNode_GetAttrVal_AsListVec2f);
485 MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool);
486 MACRO_ATTRREAD_LOOPEND;
487
488 // if "USE" defined then find already defined element.
489 if(!use.empty())
490 {
491 MACRO_USE_CHECKANDAPPLY(def, use, ENET_TriangleSet2D, ne);
492 }
493 else
494 {
495 if(vertices.size() % 3) throw DeadlyImportError("TriangleSet2D. Not enough points for defining triangle.");
496
497 // create and if needed - define new geometry object.
498 ne = new CX3DImporter_NodeElement_Geometry2D(CX3DImporter_NodeElement::ENET_TriangleSet2D, NodeElement_Cur);
499 if(!def.empty()) ne->ID = def;
500
501 // convert vec2 to vec3
502 for(std::list<aiVector2D>::iterator it2 = vertices.begin(); it2 != vertices.end(); it2++)
503 {
504 ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices.push_back(aiVector3D(it2->x, it2->y, 0));
505 }
506
507 ((CX3DImporter_NodeElement_Geometry2D*)ne)->Solid = solid;
508 ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = 3;
509 // check for X3DMetadataObject childs.
510 if(!mReader->isEmptyElement())
511 ParseNode_Metadata(ne, "TriangleSet2D");
512 else
513 NodeElement_Cur->Child.push_back(ne);// add made object as child to current element
514
515 NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
516 }// if(!use.empty()) else
517}
518
519}// namespace Assimp
520
521#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER
522