X3DImporter_Geometry2D.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. /// \file X3DImporter_Geometry2D.cpp
  2. /// \brief Parsing data from nodes of "Geometry2D" set of X3D.
  3. /// \date 2015-2016
  4. /// \author [email protected]
  5. #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
  6. #include "X3DImporter.hpp"
  7. #include "X3DImporter_Node.hpp"
  8. #include "X3DImporter_Macro.hpp"
  9. namespace Assimp
  10. {
  11. // <Arc2D
  12. // DEF="" ID
  13. // USE="" IDREF
  14. // endAngle="1.570796" SFFloat [initializeOnly]
  15. // radius="1" SFFloat [initializeOnly]
  16. // startAngle="0" SFFloat [initializeOnly]
  17. // />
  18. // 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
  19. // 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
  20. // counterclockwise to the endAngle. The values of startAngle and endAngle shall be in the range [-2pi, 2pi] radians (or the equivalent if a different
  21. // angle base unit has been specified). If startAngle and endAngle have the same value, a circle is specified.
  22. void X3DImporter::ParseNode_Geometry2D_Arc2D()
  23. {
  24. std::string def, use;
  25. float endAngle = AI_MATH_HALF_PI_F;
  26. float radius = 1;
  27. float startAngle = 0;
  28. CX3DImporter_NodeElement* ne;
  29. MACRO_ATTRREAD_LOOPBEG;
  30. MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
  31. MACRO_ATTRREAD_CHECK_RET("endAngle", endAngle, XML_ReadNode_GetAttrVal_AsFloat);
  32. MACRO_ATTRREAD_CHECK_RET("radius", radius, XML_ReadNode_GetAttrVal_AsFloat);
  33. MACRO_ATTRREAD_CHECK_RET("startAngle", startAngle, XML_ReadNode_GetAttrVal_AsFloat);
  34. MACRO_ATTRREAD_LOOPEND;
  35. // if "USE" defined then find already defined element.
  36. if(!use.empty())
  37. {
  38. MACRO_USE_CHECKANDAPPLY(def, use, ENET_Arc2D, ne);
  39. }
  40. else
  41. {
  42. // create and if needed - define new geometry object.
  43. ne = new CX3DImporter_NodeElement_Geometry2D(CX3DImporter_NodeElement::ENET_Arc2D, NodeElement_Cur);
  44. if(!def.empty()) ne->ID = def;
  45. // create point list of geometry object and convert it to line set.
  46. std::list<aiVector3D> tlist;
  47. GeometryHelper_Make_Arc2D(startAngle, endAngle, radius, 10, tlist);///TODO: IME - AI_CONFIG for NumSeg
  48. GeometryHelper_Extend_PointToLine(tlist, ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices);
  49. ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = 2;
  50. // check for X3DMetadataObject childs.
  51. if(!mReader->isEmptyElement())
  52. ParseNode_Metadata(ne, "Arc2D");
  53. else
  54. NodeElement_Cur->Child.push_back(ne);// add made object as child to current element
  55. NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
  56. }// if(!use.empty()) else
  57. }
  58. // <ArcClose2D
  59. // DEF="" ID
  60. // USE="" IDREF
  61. // closureType="PIE" SFString [initializeOnly], {"PIE", "CHORD"}
  62. // endAngle="1.570796" SFFloat [initializeOnly]
  63. // radius="1" SFFloat [initializeOnly]
  64. // solid="false" SFBool [initializeOnly]
  65. // startAngle="0" SFFloat [initializeOnly]
  66. // />
  67. // 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
  68. // 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
  69. // 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
  70. // 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
  71. // been specified). If startAngle and endAngle have the same value, a circle is specified and closureType is ignored. If the absolute difference between
  72. // 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.
  73. // 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
  74. // 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
  75. // 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
  76. // 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.
  77. void X3DImporter::ParseNode_Geometry2D_ArcClose2D()
  78. {
  79. std::string def, use;
  80. std::string closureType("PIE");
  81. float endAngle = AI_MATH_HALF_PI_F;
  82. float radius = 1;
  83. bool solid = false;
  84. float startAngle = 0;
  85. CX3DImporter_NodeElement* ne;
  86. MACRO_ATTRREAD_LOOPBEG;
  87. MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
  88. MACRO_ATTRREAD_CHECK_RET("closureType", closureType, mReader->getAttributeValue);
  89. MACRO_ATTRREAD_CHECK_RET("endAngle", endAngle, XML_ReadNode_GetAttrVal_AsFloat);
  90. MACRO_ATTRREAD_CHECK_RET("radius", radius, XML_ReadNode_GetAttrVal_AsFloat);
  91. MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool);
  92. MACRO_ATTRREAD_CHECK_RET("startAngle", startAngle, XML_ReadNode_GetAttrVal_AsFloat);
  93. MACRO_ATTRREAD_LOOPEND;
  94. // if "USE" defined then find already defined element.
  95. if(!use.empty())
  96. {
  97. MACRO_USE_CHECKANDAPPLY(def, use, ENET_ArcClose2D, ne);
  98. }
  99. else
  100. {
  101. // create and if needed - define new geometry object.
  102. ne = new CX3DImporter_NodeElement_Geometry2D(CX3DImporter_NodeElement::ENET_ArcClose2D, NodeElement_Cur);
  103. if(!def.empty()) ne->ID = def;
  104. ((CX3DImporter_NodeElement_Geometry2D*)ne)->Solid = solid;
  105. // create point list of geometry object.
  106. GeometryHelper_Make_Arc2D(startAngle, endAngle, radius, 10, ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices);///TODO: IME - AI_CONFIG for NumSeg
  107. // add chord or two radiuses only if not a circle was defined
  108. if(!((fabs(endAngle - startAngle) >= AI_MATH_TWO_PI_F) || (endAngle == startAngle)))
  109. {
  110. std::list<aiVector3D>& vlist = ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices;// just short alias.
  111. if((closureType == "PIE") || (closureType == "\"PIE\""))
  112. vlist.push_back(aiVector3D(0, 0, 0));// center point - first radial line
  113. else if((closureType != "CHORD") && (closureType != "\"CHORD\""))
  114. Throw_IncorrectAttrValue("closureType");
  115. vlist.push_back(*vlist.begin());// arc first point - chord from first to last point of arc(if CHORD) or second radial line(if PIE).
  116. }
  117. ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices.size();
  118. // check for X3DMetadataObject childs.
  119. if(!mReader->isEmptyElement())
  120. ParseNode_Metadata(ne, "ArcClose2D");
  121. else
  122. NodeElement_Cur->Child.push_back(ne);// add made object as child to current element
  123. NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
  124. }// if(!use.empty()) else
  125. }
  126. // <Circle2D
  127. // DEF="" ID
  128. // USE="" IDREF
  129. // radius="1" SFFloat [initializeOnly]
  130. // />
  131. void X3DImporter::ParseNode_Geometry2D_Circle2D()
  132. {
  133. std::string def, use;
  134. float radius = 1;
  135. CX3DImporter_NodeElement* ne;
  136. MACRO_ATTRREAD_LOOPBEG;
  137. MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
  138. MACRO_ATTRREAD_CHECK_RET("radius", radius, XML_ReadNode_GetAttrVal_AsFloat);
  139. MACRO_ATTRREAD_LOOPEND;
  140. // if "USE" defined then find already defined element.
  141. if(!use.empty())
  142. {
  143. MACRO_USE_CHECKANDAPPLY(def, use, ENET_Circle2D, ne);
  144. }
  145. else
  146. {
  147. // create and if needed - define new geometry object.
  148. ne = new CX3DImporter_NodeElement_Geometry2D(CX3DImporter_NodeElement::ENET_Circle2D, NodeElement_Cur);
  149. if(!def.empty()) ne->ID = def;
  150. // create point list of geometry object and convert it to line set.
  151. std::list<aiVector3D> tlist;
  152. GeometryHelper_Make_Arc2D(0, 0, radius, 10, tlist);///TODO: IME - AI_CONFIG for NumSeg
  153. GeometryHelper_Extend_PointToLine(tlist, ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices);
  154. ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = 2;
  155. // check for X3DMetadataObject childs.
  156. if(!mReader->isEmptyElement())
  157. ParseNode_Metadata(ne, "Circle2D");
  158. else
  159. NodeElement_Cur->Child.push_back(ne);// add made object as child to current element
  160. NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
  161. }// if(!use.empty()) else
  162. }
  163. // <Disk2D
  164. // DEF="" ID
  165. // USE="" IDREF
  166. // innerRadius="0" SFFloat [initializeOnly]
  167. // outerRadius="1" SFFloat [initializeOnly]
  168. // solid="false" SFBool [initializeOnly]
  169. // />
  170. // 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
  171. // outer dimension of the Disk2D. The innerRadius field specifies the inner dimension of the Disk2D. The value of outerRadius shall be greater than zero.
  172. // 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
  173. // filled. Otherwise, the area within the innerRadius forms a hole in the Disk2D. If innerRadius is equal to outerRadius, a solid circular line shall
  174. // 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
  175. // 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.
  176. void X3DImporter::ParseNode_Geometry2D_Disk2D()
  177. {
  178. std::string def, use;
  179. float innerRadius = 0;
  180. float outerRadius = 1;
  181. bool solid = false;
  182. CX3DImporter_NodeElement* ne;
  183. MACRO_ATTRREAD_LOOPBEG;
  184. MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
  185. MACRO_ATTRREAD_CHECK_RET("innerRadius", innerRadius, XML_ReadNode_GetAttrVal_AsFloat);
  186. MACRO_ATTRREAD_CHECK_RET("outerRadius", outerRadius, XML_ReadNode_GetAttrVal_AsFloat);
  187. MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool);
  188. MACRO_ATTRREAD_LOOPEND;
  189. // if "USE" defined then find already defined element.
  190. if(!use.empty())
  191. {
  192. MACRO_USE_CHECKANDAPPLY(def, use, ENET_Disk2D, ne);
  193. }
  194. else
  195. {
  196. std::list<aiVector3D> tlist_o, tlist_i;
  197. if(innerRadius > outerRadius) Throw_IncorrectAttrValue("innerRadius");
  198. // create and if needed - define new geometry object.
  199. ne = new CX3DImporter_NodeElement_Geometry2D(CX3DImporter_NodeElement::ENET_Disk2D, NodeElement_Cur);
  200. if(!def.empty()) ne->ID = def;
  201. // create point list of geometry object.
  202. ///TODO: IME - AI_CONFIG for NumSeg
  203. GeometryHelper_Make_Arc2D(0, 0, outerRadius, 10, tlist_o);// outer circle
  204. if(innerRadius == 0.0f)
  205. {// make filled disk
  206. // in tlist_o we already have points of circle. just copy it and sign as polygon.
  207. ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices = tlist_o;
  208. ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = tlist_o.size();
  209. }
  210. else if(innerRadius == outerRadius)
  211. {// make circle
  212. // in tlist_o we already have points of circle. convert it to line set.
  213. GeometryHelper_Extend_PointToLine(tlist_o, ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices);
  214. ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = 2;
  215. }
  216. else
  217. {// make disk
  218. std::list<aiVector3D>& vlist = ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices;// just short alias.
  219. GeometryHelper_Make_Arc2D(0, 0, innerRadius, 10, tlist_i);// inner circle
  220. //
  221. // create quad list from two point lists
  222. //
  223. if(tlist_i.size() < 2) throw DeadlyImportError("Disk2D. Not enough points for creating quad list.");// tlist_i and tlist_o has equal size.
  224. // add all quads except last
  225. for(std::list<aiVector3D>::iterator it_i = tlist_i.begin(), it_o = tlist_o.begin(); it_i != tlist_i.end();)
  226. {
  227. // do not forget - CCW direction
  228. vlist.push_back(*it_i++);// 1st point
  229. vlist.push_back(*it_o++);// 2nd point
  230. vlist.push_back(*it_o);// 3rd point
  231. vlist.push_back(*it_i);// 4th point
  232. }
  233. // add last quad
  234. vlist.push_back(*tlist_i.end());// 1st point
  235. vlist.push_back(*tlist_o.end());// 2nd point
  236. vlist.push_back(*tlist_o.begin());// 3rd point
  237. vlist.push_back(*tlist_o.begin());// 4th point
  238. ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = 4;
  239. }
  240. ((CX3DImporter_NodeElement_Geometry2D*)ne)->Solid = solid;
  241. // check for X3DMetadataObject childs.
  242. if(!mReader->isEmptyElement())
  243. ParseNode_Metadata(ne, "Disk2D");
  244. else
  245. NodeElement_Cur->Child.push_back(ne);// add made object as child to current element
  246. NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
  247. }// if(!use.empty()) else
  248. }
  249. // <Polyline2D
  250. // DEF="" ID
  251. // USE="" IDREF
  252. // lineSegments="" MFVec2F [intializeOnly]
  253. // />
  254. void X3DImporter::ParseNode_Geometry2D_Polyline2D()
  255. {
  256. std::string def, use;
  257. std::list<aiVector2D> lineSegments;
  258. CX3DImporter_NodeElement* ne;
  259. MACRO_ATTRREAD_LOOPBEG;
  260. MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
  261. MACRO_ATTRREAD_CHECK_REF("lineSegments", lineSegments, XML_ReadNode_GetAttrVal_AsListVec2f);
  262. MACRO_ATTRREAD_LOOPEND;
  263. // if "USE" defined then find already defined element.
  264. if(!use.empty())
  265. {
  266. MACRO_USE_CHECKANDAPPLY(def, use, ENET_Polyline2D, ne);
  267. }
  268. else
  269. {
  270. // create and if needed - define new geometry object.
  271. ne = new CX3DImporter_NodeElement_Geometry2D(CX3DImporter_NodeElement::ENET_Polyline2D, NodeElement_Cur);
  272. if(!def.empty()) ne->ID = def;
  273. //
  274. // convert read point list of geometry object to line set.
  275. //
  276. std::list<aiVector3D> tlist;
  277. // convert vec2 to vec3
  278. for(std::list<aiVector2D>::iterator it2 = lineSegments.begin(); it2 != lineSegments.end(); it2++) tlist.push_back(aiVector3D(it2->x, it2->y, 0));
  279. // convert point set to line set
  280. GeometryHelper_Extend_PointToLine(tlist, ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices);
  281. ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = 2;
  282. // check for X3DMetadataObject childs.
  283. if(!mReader->isEmptyElement())
  284. ParseNode_Metadata(ne, "Polyline2D");
  285. else
  286. NodeElement_Cur->Child.push_back(ne);// add made object as child to current element
  287. NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
  288. }// if(!use.empty()) else
  289. }
  290. // <Polypoint2D
  291. // DEF="" ID
  292. // USE="" IDREF
  293. // point="" MFVec2F [inputOutput]
  294. // />
  295. void X3DImporter::ParseNode_Geometry2D_Polypoint2D()
  296. {
  297. std::string def, use;
  298. std::list<aiVector2D> point;
  299. CX3DImporter_NodeElement* ne;
  300. MACRO_ATTRREAD_LOOPBEG;
  301. MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
  302. MACRO_ATTRREAD_CHECK_REF("point", point, XML_ReadNode_GetAttrVal_AsListVec2f);
  303. MACRO_ATTRREAD_LOOPEND;
  304. // if "USE" defined then find already defined element.
  305. if(!use.empty())
  306. {
  307. MACRO_USE_CHECKANDAPPLY(def, use, ENET_Polypoint2D, ne);
  308. }
  309. else
  310. {
  311. // create and if needed - define new geometry object.
  312. ne = new CX3DImporter_NodeElement_Geometry2D(CX3DImporter_NodeElement::ENET_Polypoint2D, NodeElement_Cur);
  313. if(!def.empty()) ne->ID = def;
  314. // convert vec2 to vec3
  315. for(std::list<aiVector2D>::iterator it2 = point.begin(); it2 != point.end(); it2++)
  316. {
  317. ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices.push_back(aiVector3D(it2->x, it2->y, 0));
  318. }
  319. ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = 1;
  320. // check for X3DMetadataObject childs.
  321. if(!mReader->isEmptyElement())
  322. ParseNode_Metadata(ne, "Polypoint2D");
  323. else
  324. NodeElement_Cur->Child.push_back(ne);// add made object as child to current element
  325. NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
  326. }// if(!use.empty()) else
  327. }
  328. // <Rectangle2D
  329. // DEF="" ID
  330. // USE="" IDREF
  331. // size="2 2" SFVec2f [initializeOnly]
  332. // solid="false" SFBool [initializeOnly]
  333. // />
  334. void X3DImporter::ParseNode_Geometry2D_Rectangle2D()
  335. {
  336. std::string def, use;
  337. aiVector2D size(2, 2);
  338. bool solid = false;
  339. CX3DImporter_NodeElement* ne;
  340. MACRO_ATTRREAD_LOOPBEG;
  341. MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
  342. MACRO_ATTRREAD_CHECK_REF("size", size, XML_ReadNode_GetAttrVal_AsVec2f);
  343. MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool);
  344. MACRO_ATTRREAD_LOOPEND;
  345. // if "USE" defined then find already defined element.
  346. if(!use.empty())
  347. {
  348. MACRO_USE_CHECKANDAPPLY(def, use, ENET_Rectangle2D, ne);
  349. }
  350. else
  351. {
  352. // create and if needed - define new geometry object.
  353. ne = new CX3DImporter_NodeElement_Geometry2D(CX3DImporter_NodeElement::ENET_Rectangle2D, NodeElement_Cur);
  354. if(!def.empty()) ne->ID = def;
  355. float x1 = -size.x / 2.0f;
  356. float x2 = size.x / 2.0f;
  357. float y1 = -size.y / 2.0f;
  358. float y2 = size.y / 2.0f;
  359. std::list<aiVector3D>& vlist = ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices;// just short alias.
  360. vlist.push_back(aiVector3D(x2, y1, 0));// 1st point
  361. vlist.push_back(aiVector3D(x2, y2, 0));// 2nd point
  362. vlist.push_back(aiVector3D(x1, y2, 0));// 3rd point
  363. vlist.push_back(aiVector3D(x1, y1, 0));// 4th point
  364. ((CX3DImporter_NodeElement_Geometry2D*)ne)->Solid = solid;
  365. ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = 4;
  366. // check for X3DMetadataObject childs.
  367. if(!mReader->isEmptyElement())
  368. ParseNode_Metadata(ne, "Rectangle2D");
  369. else
  370. NodeElement_Cur->Child.push_back(ne);// add made object as child to current element
  371. NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
  372. }// if(!use.empty()) else
  373. }
  374. // <TriangleSet2D
  375. // DEF="" ID
  376. // USE="" IDREF
  377. // solid="false" SFBool [initializeOnly]
  378. // vertices="" MFVec2F [inputOutput]
  379. // />
  380. void X3DImporter::ParseNode_Geometry2D_TriangleSet2D()
  381. {
  382. std::string def, use;
  383. bool solid = false;
  384. std::list<aiVector2D> vertices;
  385. CX3DImporter_NodeElement* ne;
  386. MACRO_ATTRREAD_LOOPBEG;
  387. MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
  388. MACRO_ATTRREAD_CHECK_REF("vertices", vertices, XML_ReadNode_GetAttrVal_AsListVec2f);
  389. MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool);
  390. MACRO_ATTRREAD_LOOPEND;
  391. // if "USE" defined then find already defined element.
  392. if(!use.empty())
  393. {
  394. MACRO_USE_CHECKANDAPPLY(def, use, ENET_TriangleSet2D, ne);
  395. }
  396. else
  397. {
  398. if(vertices.size() % 3) throw DeadlyImportError("TriangleSet2D. Not enough points for defining triangle.");
  399. // create and if needed - define new geometry object.
  400. ne = new CX3DImporter_NodeElement_Geometry2D(CX3DImporter_NodeElement::ENET_TriangleSet2D, NodeElement_Cur);
  401. if(!def.empty()) ne->ID = def;
  402. // convert vec2 to vec3
  403. for(std::list<aiVector2D>::iterator it2 = vertices.begin(); it2 != vertices.end(); it2++)
  404. {
  405. ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices.push_back(aiVector3D(it2->x, it2->y, 0));
  406. }
  407. ((CX3DImporter_NodeElement_Geometry2D*)ne)->Solid = solid;
  408. ((CX3DImporter_NodeElement_Geometry2D*)ne)->NumIndices = 3;
  409. // check for X3DMetadataObject childs.
  410. if(!mReader->isEmptyElement())
  411. ParseNode_Metadata(ne, "TriangleSet2D");
  412. else
  413. NodeElement_Cur->Child.push_back(ne);// add made object as child to current element
  414. NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
  415. }// if(!use.empty()) else
  416. }
  417. }// namespace Assimp
  418. #endif // !ASSIMP_BUILD_NO_X3D_IMPORTER