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
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
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
42/** @file IFC.cpp
43 * @brief Implementation of the Industry Foundation Classes loader.
44 */
45
46#ifndef INCLUDED_IFCUTIL_H
47#define INCLUDED_IFCUTIL_H
48
49#include "IFCReaderGen.h"
50#include "IFCLoader.h"
51#include "STEPFile.h"
52#include <assimp/mesh.h>
53#include <assimp/material.h>
54
55struct aiNode;
56
57namespace Assimp {
58namespace IFC {
59
60 typedef double IfcFloat;
61
62 // IfcFloat-precision math data types
63 typedef aiVector2t<IfcFloat> IfcVector2;
64 typedef aiVector3t<IfcFloat> IfcVector3;
65 typedef aiMatrix4x4t<IfcFloat> IfcMatrix4;
66 typedef aiMatrix3x3t<IfcFloat> IfcMatrix3;
67 typedef aiColor4t<IfcFloat> IfcColor4;
68
69
70// ------------------------------------------------------------------------------------------------
71// Helper for std::for_each to delete all heap-allocated items in a container
72// ------------------------------------------------------------------------------------------------
73template<typename T>
74struct delete_fun
75{
76 void operator()(T* del) {
77 delete del;
78 }
79};
80
81
82
83// ------------------------------------------------------------------------------------------------
84// Helper used during mesh construction. Aids at creating aiMesh'es out of relatively few polygons.
85// ------------------------------------------------------------------------------------------------
86struct TempMesh
87{
88 std::vector<IfcVector3> verts;
89 std::vector<unsigned int> vertcnt;
90
91 // utilities
92 aiMesh* ToMesh();
93 void Clear();
94 void Transform(const IfcMatrix4& mat);
95 IfcVector3 Center() const;
96 void Append(const TempMesh& other);
97
98 bool IsEmpty() const {
99 return verts.empty() && vertcnt.empty();
100 }
101
102 void RemoveAdjacentDuplicates();
103 void RemoveDegenerates();
104
105 void FixupFaceOrientation();
106
107 static IfcVector3 ComputePolygonNormal(const IfcVector3* vtcs, size_t cnt, bool normalize = true);
108 IfcVector3 ComputeLastPolygonNormal(bool normalize = true) const;
109 void ComputePolygonNormals(std::vector<IfcVector3>& normals, bool normalize = true, size_t ofs = 0) const;
110
111 void Swap(TempMesh& other);
112};
113
114
115// ------------------------------------------------------------------------------------------------
116// Temporary representation of an opening in a wall or a floor
117// ------------------------------------------------------------------------------------------------
118struct TempOpening
119{
120 const IFC::IfcSolidModel* solid;
121 IfcVector3 extrusionDir;
122
123 std::shared_ptr<TempMesh> profileMesh;
124 std::shared_ptr<TempMesh> profileMesh2D;
125
126 // list of points generated for this opening. This is used to
127 // create connections between two opposing holes created
128 // from a single opening instance (two because walls tend to
129 // have two sides). If !empty(), the other side of the wall
130 // has already been processed.
131 std::vector<IfcVector3> wallPoints;
132
133 // ------------------------------------------------------------------------------
134 TempOpening()
135 : solid()
136 , extrusionDir()
137 , profileMesh()
138 {
139 }
140
141 // ------------------------------------------------------------------------------
142 TempOpening(const IFC::IfcSolidModel* solid,IfcVector3 extrusionDir,
143 std::shared_ptr<TempMesh> profileMesh,
144 std::shared_ptr<TempMesh> profileMesh2D)
145 : solid(solid)
146 , extrusionDir(extrusionDir)
147 , profileMesh(profileMesh)
148 , profileMesh2D(profileMesh2D)
149 {
150 }
151
152 // ------------------------------------------------------------------------------
153 void Transform(const IfcMatrix4& mat); // defined later since TempMesh is not complete yet
154
155
156
157 // ------------------------------------------------------------------------------
158 // Helper to sort openings by distance from a given base point
159 struct DistanceSorter {
160
161 DistanceSorter(const IfcVector3& base) : base(base) {}
162
163 bool operator () (const TempOpening& a, const TempOpening& b) const {
164 return (a.profileMesh->Center()-base).SquareLength() < (b.profileMesh->Center()-base).SquareLength();
165 }
166
167 IfcVector3 base;
168 };
169};
170
171
172// ------------------------------------------------------------------------------------------------
173// Intermediate data storage during conversion. Keeps everything and a bit more.
174// ------------------------------------------------------------------------------------------------
175struct ConversionData
176{
177 ConversionData(const STEP::DB& db, const IFC::IfcProject& proj, aiScene* out,const IFCImporter::Settings& settings)
178 : len_scale(1.0)
179 , angle_scale(-1.0)
180 , db(db)
181 , proj(proj)
182 , out(out)
183 , settings(settings)
184 , apply_openings()
185 , collect_openings()
186 {}
187
188 ~ConversionData() {
189 std::for_each(meshes.begin(),meshes.end(),delete_fun<aiMesh>());
190 std::for_each(materials.begin(),materials.end(),delete_fun<aiMaterial>());
191 }
192
193 IfcFloat len_scale, angle_scale;
194 bool plane_angle_in_radians;
195
196 const STEP::DB& db;
197 const IFC::IfcProject& proj;
198 aiScene* out;
199
200 IfcMatrix4 wcs;
201 std::vector<aiMesh*> meshes;
202 std::vector<aiMaterial*> materials;
203
204 struct MeshCacheIndex {
205 const IFC::IfcRepresentationItem* item; unsigned int matindex;
206 MeshCacheIndex() : item(NULL), matindex(0) { }
207 MeshCacheIndex(const IFC::IfcRepresentationItem* i, unsigned int mi) : item(i), matindex(mi) { }
208 bool operator == (const MeshCacheIndex& o) const { return item == o.item && matindex == o.matindex; }
209 bool operator < (const MeshCacheIndex& o) const { return item < o.item || (item == o.item && matindex < o.matindex); }
210 };
211 typedef std::map<MeshCacheIndex, std::vector<unsigned int> > MeshCache;
212 MeshCache cached_meshes;
213
214 typedef std::map<const IFC::IfcSurfaceStyle*, unsigned int> MaterialCache;
215 MaterialCache cached_materials;
216
217 const IFCImporter::Settings& settings;
218
219 // Intermediate arrays used to resolve openings in walls: only one of them
220 // can be given at a time. apply_openings if present if the current element
221 // is a wall and needs its openings to be poured into its geometry while
222 // collect_openings is present only if the current element is an
223 // IfcOpeningElement, for which all the geometry needs to be preserved
224 // for later processing by a parent, which is a wall.
225 std::vector<TempOpening>* apply_openings;
226 std::vector<TempOpening>* collect_openings;
227
228 std::set<uint64_t> already_processed;
229};
230
231
232// ------------------------------------------------------------------------------------------------
233// Binary predicate to compare vectors with a given, quadratic epsilon.
234// ------------------------------------------------------------------------------------------------
235struct FuzzyVectorCompare {
236
237 FuzzyVectorCompare(IfcFloat epsilon) : epsilon(epsilon) {}
238 bool operator()(const IfcVector3& a, const IfcVector3& b) {
239 return std::abs((a-b).SquareLength()) < epsilon;
240 }
241
242 const IfcFloat epsilon;
243};
244
245
246// ------------------------------------------------------------------------------------------------
247// Ordering predicate to totally order R^2 vectors first by x and then by y
248// ------------------------------------------------------------------------------------------------
249struct XYSorter {
250
251 // sort first by X coordinates, then by Y coordinates
252 bool operator () (const IfcVector2&a, const IfcVector2& b) const {
253 if (a.x == b.x) {
254 return a.y < b.y;
255 }
256 return a.x < b.x;
257 }
258};
259
260
261
262// conversion routines for common IFC entities, implemented in IFCUtil.cpp
263void ConvertColor(aiColor4D& out, const IfcColourRgb& in);
264void ConvertColor(aiColor4D& out, const IfcColourOrFactor& in,ConversionData& conv,const aiColor4D* base);
265void ConvertCartesianPoint(IfcVector3& out, const IfcCartesianPoint& in);
266void ConvertDirection(IfcVector3& out, const IfcDirection& in);
267void ConvertVector(IfcVector3& out, const IfcVector& in);
268void AssignMatrixAxes(IfcMatrix4& out, const IfcVector3& x, const IfcVector3& y, const IfcVector3& z);
269void ConvertAxisPlacement(IfcMatrix4& out, const IfcAxis2Placement3D& in);
270void ConvertAxisPlacement(IfcMatrix4& out, const IfcAxis2Placement2D& in);
271void ConvertAxisPlacement(IfcVector3& axis, IfcVector3& pos, const IFC::IfcAxis1Placement& in);
272void ConvertAxisPlacement(IfcMatrix4& out, const IfcAxis2Placement& in, ConversionData& conv);
273void ConvertTransformOperator(IfcMatrix4& out, const IfcCartesianTransformationOperator& op);
274bool IsTrue(const EXPRESS::BOOLEAN& in);
275IfcFloat ConvertSIPrefix(const std::string& prefix);
276
277
278// IFCProfile.cpp
279bool ProcessProfile(const IfcProfileDef& prof, TempMesh& meshout, ConversionData& conv);
280bool ProcessCurve(const IfcCurve& curve, TempMesh& meshout, ConversionData& conv);
281
282// IFCMaterial.cpp
283unsigned int ProcessMaterials(uint64_t id, unsigned int prevMatId, ConversionData& conv, bool forceDefaultMat);
284
285// IFCGeometry.cpp
286IfcMatrix3 DerivePlaneCoordinateSpace(const TempMesh& curmesh, bool& ok, IfcVector3& norOut);
287bool ProcessRepresentationItem(const IfcRepresentationItem& item, unsigned int matid, std::vector<unsigned int>& mesh_indices, ConversionData& conv);
288void AssignAddedMeshes(std::vector<unsigned int>& mesh_indices,aiNode* nd,ConversionData& /*conv*/);
289
290void ProcessSweptAreaSolid(const IfcSweptAreaSolid& swept, TempMesh& meshout,
291 ConversionData& conv);
292
293void ProcessExtrudedAreaSolid(const IfcExtrudedAreaSolid& solid, TempMesh& result,
294 ConversionData& conv, bool collect_openings);
295
296// IFCBoolean.cpp
297
298void ProcessBoolean(const IfcBooleanResult& boolean, TempMesh& result, ConversionData& conv);
299void ProcessBooleanHalfSpaceDifference(const IfcHalfSpaceSolid* hs, TempMesh& result,
300 const TempMesh& first_operand,
301 ConversionData& conv);
302
303void ProcessPolygonalBoundedBooleanHalfSpaceDifference(const IfcPolygonalBoundedHalfSpace* hs, TempMesh& result,
304 const TempMesh& first_operand,
305 ConversionData& conv);
306void ProcessBooleanExtrudedAreaSolidDifference(const IfcExtrudedAreaSolid* as, TempMesh& result,
307 const TempMesh& first_operand,
308 ConversionData& conv);
309
310
311// IFCOpenings.cpp
312
313bool GenerateOpenings(std::vector<TempOpening>& openings,
314 const std::vector<IfcVector3>& nors,
315 TempMesh& curmesh,
316 bool check_intersection,
317 bool generate_connection_geometry,
318 const IfcVector3& wall_extrusion_axis = IfcVector3(0,1,0));
319
320
321
322// IFCCurve.cpp
323
324// ------------------------------------------------------------------------------------------------
325// Custom exception for use by members of the Curve class
326// ------------------------------------------------------------------------------------------------
327class CurveError
328{
329public:
330 CurveError(const std::string& s)
331 : s(s)
332 {
333 }
334
335 std::string s;
336};
337
338
339// ------------------------------------------------------------------------------------------------
340// Temporary representation for an arbitrary sub-class of IfcCurve. Used to sample the curves
341// to obtain a list of line segments.
342// ------------------------------------------------------------------------------------------------
343class Curve
344{
345protected:
346
347 Curve(const IfcCurve& base_entity, ConversionData& conv)
348 : base_entity(base_entity)
349 , conv(conv)
350 {}
351
352public:
353
354 typedef std::pair<IfcFloat, IfcFloat> ParamRange;
355
356public:
357
358
359 virtual ~Curve() {}
360
361
362 // check if a curve is closed
363 virtual bool IsClosed() const = 0;
364
365 // evaluate the curve at the given parametric position
366 virtual IfcVector3 Eval(IfcFloat p) const = 0;
367
368 // try to match a point on the curve to a given parameter
369 // for self-intersecting curves, the result is not ambiguous and
370 // it is undefined which parameter is returned.
371 virtual bool ReverseEval(const IfcVector3& val, IfcFloat& paramOut) const;
372
373 // get the range of the curve (both inclusive).
374 // +inf and -inf are valid return values, the curve is not bounded in such a case.
375 virtual std::pair<IfcFloat,IfcFloat> GetParametricRange() const = 0;
376 IfcFloat GetParametricRangeDelta() const;
377
378 // estimate the number of sample points that this curve will require
379 virtual size_t EstimateSampleCount(IfcFloat start,IfcFloat end) const;
380
381 // intelligently sample the curve based on the current settings
382 // and append the result to the mesh
383 virtual void SampleDiscrete(TempMesh& out,IfcFloat start,IfcFloat end) const;
384
385#ifdef ASSIMP_BUILD_DEBUG
386 // check if a particular parameter value lies within the well-defined range
387 bool InRange(IfcFloat) const;
388#endif
389
390public:
391
392 static Curve* Convert(const IFC::IfcCurve&,ConversionData& conv);
393
394protected:
395
396 const IfcCurve& base_entity;
397 ConversionData& conv;
398};
399
400
401// --------------------------------------------------------------------------------
402// A BoundedCurve always holds the invariant that GetParametricRange()
403// never returns infinite values.
404// --------------------------------------------------------------------------------
405class BoundedCurve : public Curve
406{
407public:
408
409 BoundedCurve(const IfcBoundedCurve& entity, ConversionData& conv)
410 : Curve(entity,conv)
411 {}
412
413public:
414
415 bool IsClosed() const;
416
417public:
418
419 // sample the entire curve
420 void SampleDiscrete(TempMesh& out) const;
421 using Curve::SampleDiscrete;
422};
423
424// IfcProfile.cpp
425bool ProcessCurve(const IfcCurve& curve, TempMesh& meshout, ConversionData& conv);
426}
427}
428
429#endif
430