/src/assimp/code/AssetLib/X3D/X3DImporter_Geometry2D.cpp
Line | Count | Source |
1 | | /* |
2 | | Open Asset Import Library (assimp) |
3 | | ---------------------------------------------------------------------- |
4 | | |
5 | | Copyright (c) 2006-2026, assimp team |
6 | | |
7 | | All rights reserved. |
8 | | |
9 | | Redistribution and use of this software in source and binary forms, |
10 | | with or without modification, are permitted provided that the |
11 | | following conditions are met: |
12 | | |
13 | | * Redistributions of source code must retain the above |
14 | | copyright notice, this list of conditions and the |
15 | | following disclaimer. |
16 | | |
17 | | * Redistributions in binary form must reproduce the above |
18 | | copyright notice, this list of conditions and the |
19 | | following disclaimer in the documentation and/or other |
20 | | materials provided with the distribution. |
21 | | |
22 | | * Neither the name of the assimp team, nor the names of its |
23 | | contributors may be used to endorse or promote products |
24 | | derived from this software without specific prior |
25 | | written permission of the assimp team. |
26 | | |
27 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
28 | | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
29 | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
30 | | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
31 | | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
32 | | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
33 | | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
34 | | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
35 | | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
36 | | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
37 | | OF 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_Macro.hpp" |
50 | | #include "X3DXmlHelper.h" |
51 | | #include "X3DGeoHelper.h" |
52 | | |
53 | | namespace Assimp { |
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. |
66 | 0 | void X3DImporter::readArc2D(XmlNode &node) { |
67 | 0 | std::string def, use; |
68 | 0 | float endAngle = AI_MATH_HALF_PI_F; |
69 | 0 | float radius = 1; |
70 | 0 | float startAngle = 0; |
71 | 0 | X3DNodeElementBase *ne(nullptr); |
72 | |
|
73 | 0 | MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use); |
74 | 0 | XmlParser::getFloatAttribute(node, "endAngle", endAngle); |
75 | 0 | XmlParser::getFloatAttribute(node, "radius", radius); |
76 | 0 | XmlParser::getFloatAttribute(node, "startAngle", startAngle); |
77 | | |
78 | | // if "USE" defined then find already defined element. |
79 | 0 | if (!use.empty()) { |
80 | 0 | ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Arc2D, ne); |
81 | 0 | } else { |
82 | | // create and if needed - define new geometry object. |
83 | 0 | ne = new X3DNodeElementGeometry2D(X3DElemType::ENET_Arc2D, mNodeElementCur); |
84 | 0 | if (!def.empty()) ne->ID = def; |
85 | | |
86 | | // create point list of geometry object and convert it to line set. |
87 | 0 | std::list<aiVector3D> tlist; |
88 | |
|
89 | 0 | X3DGeoHelper::make_arc2D(startAngle, endAngle, radius, 10, tlist); ///TODO: IME - AI_CONFIG for NumSeg |
90 | 0 | X3DGeoHelper::extend_point_to_line(tlist, ((X3DNodeElementGeometry2D *)ne)->Vertices); |
91 | 0 | ((X3DNodeElementGeometry2D *)ne)->NumIndices = 2; |
92 | | // check for X3DMetadataObject childs. |
93 | 0 | if (!isNodeEmpty(node)) |
94 | 0 | childrenReadMetadata(node, ne, "Arc2D"); |
95 | 0 | else |
96 | 0 | mNodeElementCur->Children.push_back(ne); // add made object as child to current element |
97 | |
|
98 | 0 | NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph |
99 | 0 | } // if(!use.empty()) else |
100 | 0 | } |
101 | | |
102 | | // <ArcClose2D |
103 | | // DEF="" ID |
104 | | // USE="" IDREF |
105 | | // closureType="PIE" SFString [initializeOnly], {"PIE", "CHORD"} |
106 | | // endAngle="1.570796" SFFloat [initializeOnly] |
107 | | // radius="1" SFFloat [initializeOnly] |
108 | | // solid="false" SFBool [initializeOnly] |
109 | | // startAngle="0" SFFloat [initializeOnly] |
110 | | // /> |
111 | | // 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 |
112 | | // 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 |
113 | | // 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 |
114 | | // 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 |
115 | | // been specified). If startAngle and endAngle have the same value, a circle is specified and closureType is ignored. If the absolute difference between |
116 | | // 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. |
117 | | // 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 |
118 | | // 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 |
119 | | // 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 |
120 | | // 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. |
121 | 0 | void X3DImporter::readArcClose2D(XmlNode &node) { |
122 | 0 | std::string def, use; |
123 | 0 | std::string closureType("PIE"); |
124 | 0 | float endAngle = AI_MATH_HALF_PI_F; |
125 | 0 | float radius = 1; |
126 | 0 | bool solid = false; |
127 | 0 | float startAngle = 0; |
128 | 0 | X3DNodeElementBase *ne(nullptr); |
129 | |
|
130 | 0 | MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use); |
131 | 0 | XmlParser::getStdStrAttribute(node, "closureType", closureType); |
132 | 0 | XmlParser::getFloatAttribute(node, "endAngle", endAngle); |
133 | 0 | XmlParser::getFloatAttribute(node, "endAngle", endAngle); |
134 | 0 | XmlParser::getFloatAttribute(node, "radius", radius); |
135 | 0 | XmlParser::getBoolAttribute(node, "solid", solid); |
136 | 0 | XmlParser::getFloatAttribute(node, "startAngle", startAngle); |
137 | | |
138 | | // if "USE" defined then find already defined element. |
139 | 0 | if (!use.empty()) { |
140 | 0 | ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_ArcClose2D, ne); |
141 | 0 | } else { |
142 | | // create and if needed - define new geometry object. |
143 | 0 | ne = new X3DNodeElementGeometry2D(X3DElemType::ENET_ArcClose2D, mNodeElementCur); |
144 | 0 | if (!def.empty()) ne->ID = def; |
145 | |
|
146 | 0 | ((X3DNodeElementGeometry2D *)ne)->Solid = solid; |
147 | | // create point list of geometry object. |
148 | 0 | X3DGeoHelper::make_arc2D(startAngle, endAngle, radius, 10, ((X3DNodeElementGeometry2D *)ne)->Vertices); ///TODO: IME - AI_CONFIG for NumSeg |
149 | | // add chord or two radiuses only if not a circle was defined |
150 | 0 | if (!((std::fabs(endAngle - startAngle) >= AI_MATH_TWO_PI_F) || (endAngle == startAngle))) { |
151 | 0 | std::list<aiVector3D> &vlist = ((X3DNodeElementGeometry2D *)ne)->Vertices; // just short alias. |
152 | |
|
153 | 0 | if ((closureType == "PIE") || (closureType == "\"PIE\"")) |
154 | 0 | vlist.emplace_back(static_cast<ai_real>(0), static_cast<ai_real>(0), static_cast<ai_real>(0)); // center point - first radial line |
155 | 0 | else if ((closureType != "CHORD") && (closureType != "\"CHORD\"")) |
156 | 0 | Throw_IncorrectAttrValue("ArcClose2D", "closureType"); |
157 | | |
158 | 0 | vlist.push_back(*vlist.begin()); // arc first point - chord from first to last point of arc(if CHORD) or second radial line(if PIE). |
159 | 0 | } |
160 | | |
161 | 0 | ((X3DNodeElementGeometry2D *)ne)->NumIndices = ((X3DNodeElementGeometry2D *)ne)->Vertices.size(); |
162 | | // check for X3DMetadataObject childs. |
163 | 0 | if (!isNodeEmpty(node)) |
164 | 0 | childrenReadMetadata(node, ne, "ArcClose2D"); |
165 | 0 | else |
166 | 0 | mNodeElementCur->Children.push_back(ne); // add made object as child to current element |
167 | |
|
168 | 0 | NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph |
169 | 0 | } // if(!use.empty()) else |
170 | 0 | } |
171 | | |
172 | | // <Circle2D |
173 | | // DEF="" ID |
174 | | // USE="" IDREF |
175 | | // radius="1" SFFloat [initializeOnly] |
176 | | // /> |
177 | 0 | void X3DImporter::readCircle2D(XmlNode &node) { |
178 | 0 | std::string def, use; |
179 | 0 | float radius = 1; |
180 | 0 | X3DNodeElementBase *ne(nullptr); |
181 | |
|
182 | 0 | MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use); |
183 | 0 | XmlParser::getFloatAttribute(node, "radius", radius); |
184 | | |
185 | | // if "USE" defined then find already defined element. |
186 | 0 | if (!use.empty()) { |
187 | 0 | ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Circle2D, ne); |
188 | 0 | } else { |
189 | | // create and if needed - define new geometry object. |
190 | 0 | ne = new X3DNodeElementGeometry2D(X3DElemType::ENET_Circle2D, mNodeElementCur); |
191 | 0 | if (!def.empty()) ne->ID = def; |
192 | | |
193 | | // create point list of geometry object and convert it to line set. |
194 | 0 | std::list<aiVector3D> tlist; |
195 | |
|
196 | 0 | X3DGeoHelper::make_arc2D(0, 0, radius, 10, tlist); ///TODO: IME - AI_CONFIG for NumSeg |
197 | 0 | X3DGeoHelper::extend_point_to_line(tlist, ((X3DNodeElementGeometry2D *)ne)->Vertices); |
198 | 0 | ((X3DNodeElementGeometry2D *)ne)->NumIndices = 2; |
199 | | // check for X3DMetadataObject childs. |
200 | 0 | if (!isNodeEmpty(node)) |
201 | 0 | childrenReadMetadata(node, ne, "Circle2D"); |
202 | 0 | else |
203 | 0 | mNodeElementCur->Children.push_back(ne); // add made object as child to current element |
204 | |
|
205 | 0 | NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph |
206 | 0 | } // if(!use.empty()) else |
207 | 0 | } |
208 | | |
209 | | // <Disk2D |
210 | | // DEF="" ID |
211 | | // USE="" IDREF |
212 | | // innerRadius="0" SFFloat [initializeOnly] |
213 | | // outerRadius="1" SFFloat [initializeOnly] |
214 | | // solid="false" SFBool [initializeOnly] |
215 | | // /> |
216 | | // 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 |
217 | | // outer dimension of the Disk2D. The innerRadius field specifies the inner dimension of the Disk2D. The value of outerRadius shall be greater than zero. |
218 | | // 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 |
219 | | // filled. Otherwise, the area within the innerRadius forms a hole in the Disk2D. If innerRadius is equal to outerRadius, a solid circular line shall |
220 | | // 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 |
221 | | // 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. |
222 | 0 | void X3DImporter::readDisk2D(XmlNode &node) { |
223 | 0 | std::string def, use; |
224 | 0 | float innerRadius = 0; |
225 | 0 | float outerRadius = 1; |
226 | 0 | bool solid = false; |
227 | 0 | X3DNodeElementBase *ne(nullptr); |
228 | |
|
229 | 0 | MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use); |
230 | 0 | XmlParser::getFloatAttribute(node, "innerRadius", innerRadius); |
231 | 0 | XmlParser::getFloatAttribute(node, "outerRadius", outerRadius); |
232 | 0 | XmlParser::getBoolAttribute(node, "solid", solid); |
233 | | |
234 | | // if "USE" defined then find already defined element. |
235 | 0 | if (!use.empty()) { |
236 | 0 | ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Disk2D, ne); |
237 | 0 | } else { |
238 | 0 | std::list<aiVector3D> tlist_o, tlist_i; |
239 | |
|
240 | 0 | if (innerRadius > outerRadius) Throw_IncorrectAttrValue("Disk2D", "innerRadius"); |
241 | | |
242 | | // create and if needed - define new geometry object. |
243 | 0 | ne = new X3DNodeElementGeometry2D(X3DElemType::ENET_Disk2D, mNodeElementCur); |
244 | 0 | if (!def.empty()) ne->ID = def; |
245 | | |
246 | | // create point list of geometry object. |
247 | | ///TODO: IME - AI_CONFIG for NumSeg |
248 | 0 | X3DGeoHelper::make_arc2D(0, 0, outerRadius, 10, tlist_o); // outer circle |
249 | 0 | if (innerRadius == 0.0f) { // make filled disk |
250 | | // in tlist_o we already have points of circle. just copy it and sign as polygon. |
251 | 0 | ((X3DNodeElementGeometry2D *)ne)->Vertices = tlist_o; |
252 | 0 | ((X3DNodeElementGeometry2D *)ne)->NumIndices = tlist_o.size(); |
253 | 0 | } else if (innerRadius == outerRadius) { // make circle |
254 | | // in tlist_o we already have points of circle. convert it to line set. |
255 | 0 | X3DGeoHelper::extend_point_to_line(tlist_o, ((X3DNodeElementGeometry2D *)ne)->Vertices); |
256 | 0 | ((X3DNodeElementGeometry2D *)ne)->NumIndices = 2; |
257 | 0 | } else { // make disk |
258 | 0 | std::list<aiVector3D> &vlist = ((X3DNodeElementGeometry2D *)ne)->Vertices; // just short alias. |
259 | |
|
260 | 0 | X3DGeoHelper::make_arc2D(0, 0, innerRadius, 10, tlist_i); // inner circle |
261 | | // |
262 | | // create quad list from two point lists |
263 | | // |
264 | 0 | if (tlist_i.size() < 2) { |
265 | | // tlist_i and tlist_o has equal size. |
266 | 0 | throw DeadlyImportError("Disk2D. Not enough points for creating quad list."); |
267 | 0 | } |
268 | | |
269 | | // add all quads except last |
270 | 0 | for (std::list<aiVector3D>::iterator it_i = tlist_i.begin(), it_o = tlist_o.begin(); it_i != tlist_i.end();) { |
271 | | // do not forget - CCW direction |
272 | 0 | vlist.emplace_back(*it_i++); // 1st point |
273 | 0 | vlist.emplace_back(*it_o++); // 2nd point |
274 | 0 | vlist.emplace_back(*it_o); // 3rd point |
275 | 0 | vlist.emplace_back(*it_i); // 4th point |
276 | 0 | } |
277 | | |
278 | | // add last quad |
279 | 0 | vlist.emplace_back(tlist_i.back()); // 1st point |
280 | 0 | vlist.emplace_back(tlist_o.back()); // 2nd point |
281 | 0 | vlist.emplace_back(tlist_o.front()); // 3rd point |
282 | 0 | vlist.emplace_back(tlist_i.front()); // 4th point |
283 | |
|
284 | 0 | ((X3DNodeElementGeometry2D *)ne)->NumIndices = 4; |
285 | 0 | } |
286 | | |
287 | 0 | ((X3DNodeElementGeometry2D *)ne)->Solid = solid; |
288 | | // check for X3DMetadataObject childs. |
289 | 0 | if (!isNodeEmpty(node)) |
290 | 0 | childrenReadMetadata(node, ne, "Disk2D"); |
291 | 0 | else |
292 | 0 | mNodeElementCur->Children.push_back(ne); // add made object as child to current element |
293 | |
|
294 | 0 | NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph |
295 | 0 | } // if(!use.empty()) else |
296 | 0 | } |
297 | | |
298 | | // <Polyline2D |
299 | | // DEF="" ID |
300 | | // USE="" IDREF |
301 | | // lineSegments="" MFVec2F [intializeOnly] |
302 | | // /> |
303 | 0 | void X3DImporter::readPolyline2D(XmlNode &node) { |
304 | 0 | std::string def, use; |
305 | 0 | std::list<aiVector2D> lineSegments; |
306 | 0 | X3DNodeElementBase *ne(nullptr); |
307 | |
|
308 | 0 | MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use); |
309 | 0 | X3DXmlHelper::getVector2DListAttribute(node, "lineSegments", lineSegments); |
310 | | |
311 | | // if "USE" defined then find already defined element. |
312 | 0 | if (!use.empty()) { |
313 | 0 | ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Polyline2D, ne); |
314 | 0 | } else { |
315 | | // create and if needed - define new geometry object. |
316 | 0 | ne = new X3DNodeElementGeometry2D(X3DElemType::ENET_Polyline2D, mNodeElementCur); |
317 | 0 | if (!def.empty()) ne->ID = def; |
318 | | |
319 | | // |
320 | | // convert read point list of geometry object to line set. |
321 | | // |
322 | 0 | std::list<aiVector3D> tlist; |
323 | | |
324 | | // convert vec2 to vec3 |
325 | 0 | for (std::list<aiVector2D>::iterator it2 = lineSegments.begin(); it2 != lineSegments.end(); ++it2) |
326 | 0 | tlist.emplace_back(it2->x, it2->y, static_cast<ai_real>(0)); |
327 | | |
328 | | // convert point set to line set |
329 | 0 | X3DGeoHelper::extend_point_to_line(tlist, ((X3DNodeElementGeometry2D *)ne)->Vertices); |
330 | 0 | ((X3DNodeElementGeometry2D *)ne)->NumIndices = 2; |
331 | | // check for X3DMetadataObject childs. |
332 | 0 | if (!isNodeEmpty(node)) |
333 | 0 | childrenReadMetadata(node, ne, "Polyline2D"); |
334 | 0 | else |
335 | 0 | mNodeElementCur->Children.push_back(ne); // add made object as child to current element |
336 | |
|
337 | 0 | NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph |
338 | 0 | } // if(!use.empty()) else |
339 | 0 | } |
340 | | |
341 | | // <Polypoint2D |
342 | | // DEF="" ID |
343 | | // USE="" IDREF |
344 | | // point="" MFVec2F [inputOutput] |
345 | | // /> |
346 | 0 | void X3DImporter::readPolypoint2D(XmlNode &node) { |
347 | 0 | std::string def, use; |
348 | 0 | std::list<aiVector2D> point; |
349 | 0 | X3DNodeElementBase *ne(nullptr); |
350 | |
|
351 | 0 | MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use); |
352 | 0 | X3DXmlHelper::getVector2DListAttribute(node, "point", point); |
353 | | |
354 | | // if "USE" defined then find already defined element. |
355 | 0 | if (!use.empty()) { |
356 | 0 | ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Polypoint2D, ne); |
357 | 0 | } else { |
358 | | // create and if needed - define new geometry object. |
359 | 0 | ne = new X3DNodeElementGeometry2D(X3DElemType::ENET_Polypoint2D, mNodeElementCur); |
360 | 0 | if (!def.empty()) ne->ID = def; |
361 | | |
362 | | // convert vec2 to vec3 |
363 | 0 | for (std::list<aiVector2D>::iterator it2 = point.begin(); it2 != point.end(); ++it2) { |
364 | 0 | ((X3DNodeElementGeometry2D *)ne)->Vertices.emplace_back(it2->x, it2->y, static_cast<ai_real>(0)); |
365 | 0 | } |
366 | |
|
367 | 0 | ((X3DNodeElementGeometry2D *)ne)->NumIndices = 1; |
368 | | // check for X3DMetadataObject childs. |
369 | 0 | if (!isNodeEmpty(node)) |
370 | 0 | childrenReadMetadata(node, ne, "Polypoint2D"); |
371 | 0 | else |
372 | 0 | mNodeElementCur->Children.push_back(ne); // add made object as child to current element |
373 | |
|
374 | 0 | NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph |
375 | 0 | } // if(!use.empty()) else |
376 | 0 | } |
377 | | |
378 | | // <Rectangle2D |
379 | | // DEF="" ID |
380 | | // USE="" IDREF |
381 | | // size="2 2" SFVec2f [initializeOnly] |
382 | | // solid="false" SFBool [initializeOnly] |
383 | | // /> |
384 | 0 | void X3DImporter::readRectangle2D(XmlNode &node) { |
385 | 0 | std::string def, use; |
386 | 0 | aiVector2D size(2, 2); |
387 | 0 | bool solid = false; |
388 | 0 | X3DNodeElementBase *ne(nullptr); |
389 | |
|
390 | 0 | MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use); |
391 | 0 | X3DXmlHelper::getVector2DAttribute(node, "size", size); |
392 | 0 | XmlParser::getBoolAttribute(node, "solid", solid); |
393 | | |
394 | | // if "USE" defined then find already defined element. |
395 | 0 | if (!use.empty()) { |
396 | 0 | ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Rectangle2D, ne); |
397 | 0 | } else { |
398 | | // create and if needed - define new geometry object. |
399 | 0 | ne = new X3DNodeElementGeometry2D(X3DElemType::ENET_Rectangle2D, mNodeElementCur); |
400 | 0 | if (!def.empty()) ne->ID = def; |
401 | |
|
402 | 0 | float x1 = -size.x / 2.0f; |
403 | 0 | float x2 = size.x / 2.0f; |
404 | 0 | float y1 = -size.y / 2.0f; |
405 | 0 | float y2 = size.y / 2.0f; |
406 | 0 | std::list<aiVector3D> &vlist = ((X3DNodeElementGeometry2D *)ne)->Vertices; // just short alias. |
407 | |
|
408 | 0 | vlist.emplace_back(x2, y1, static_cast<ai_real>(0)); // 1st point |
409 | 0 | vlist.emplace_back(x2, y2, static_cast<ai_real>(0)); // 2nd point |
410 | 0 | vlist.emplace_back(x1, y2, static_cast<ai_real>(0)); // 3rd point |
411 | 0 | vlist.emplace_back(x1, y1, static_cast<ai_real>(0)); // 4th point |
412 | 0 | ((X3DNodeElementGeometry2D *)ne)->Solid = solid; |
413 | 0 | ((X3DNodeElementGeometry2D *)ne)->NumIndices = 4; |
414 | | // check for X3DMetadataObject childs. |
415 | 0 | if (!isNodeEmpty(node)) |
416 | 0 | childrenReadMetadata(node, ne, "Rectangle2D"); |
417 | 0 | else |
418 | 0 | mNodeElementCur->Children.push_back(ne); // add made object as child to current element |
419 | |
|
420 | 0 | NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph |
421 | 0 | } // if(!use.empty()) else |
422 | 0 | } |
423 | | |
424 | | // <TriangleSet2D |
425 | | // DEF="" ID |
426 | | // USE="" IDREF |
427 | | // solid="false" SFBool [initializeOnly] |
428 | | // vertices="" MFVec2F [inputOutput] |
429 | | // /> |
430 | 0 | void X3DImporter::readTriangleSet2D(XmlNode &node) { |
431 | 0 | std::string def, use; |
432 | 0 | bool solid = false; |
433 | 0 | std::list<aiVector2D> vertices; |
434 | 0 | X3DNodeElementBase *ne(nullptr); |
435 | |
|
436 | 0 | MACRO_ATTRREAD_CHECKUSEDEF_RET(node, def, use); |
437 | 0 | X3DXmlHelper::getVector2DListAttribute(node, "vertices", vertices); |
438 | 0 | XmlParser::getBoolAttribute(node, "solid", solid); |
439 | | |
440 | | // if "USE" defined then find already defined element. |
441 | 0 | if (!use.empty()) { |
442 | 0 | ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_TriangleSet2D, ne); |
443 | 0 | } else { |
444 | 0 | if (vertices.size() % 3) throw DeadlyImportError("TriangleSet2D. Not enough points for defining triangle."); |
445 | | |
446 | | // create and if needed - define new geometry object. |
447 | 0 | ne = new X3DNodeElementGeometry2D(X3DElemType::ENET_TriangleSet2D, mNodeElementCur); |
448 | 0 | if (!def.empty()) ne->ID = def; |
449 | | |
450 | | // convert vec2 to vec3 |
451 | 0 | for (std::list<aiVector2D>::iterator it2 = vertices.begin(); it2 != vertices.end(); ++it2) { |
452 | 0 | ((X3DNodeElementGeometry2D *)ne)->Vertices.emplace_back(it2->x, it2->y, static_cast<ai_real>(0)); |
453 | 0 | } |
454 | |
|
455 | 0 | ((X3DNodeElementGeometry2D *)ne)->Solid = solid; |
456 | 0 | ((X3DNodeElementGeometry2D *)ne)->NumIndices = 3; |
457 | | // check for X3DMetadataObject childs. |
458 | 0 | if (!isNodeEmpty(node)) |
459 | 0 | childrenReadMetadata(node, ne, "TriangleSet2D"); |
460 | 0 | else |
461 | 0 | mNodeElementCur->Children.push_back(ne); // add made object as child to current element |
462 | |
|
463 | 0 | NodeElement_List.push_back(ne); // add element to node element list because its a new object in graph |
464 | 0 | } // if(!use.empty()) else |
465 | 0 | } |
466 | | |
467 | | } // namespace Assimp |
468 | | |
469 | | #endif // !ASSIMP_BUILD_NO_X3D_IMPORTER |