1 /*
2 Open Asset Import Library (assimp)
3 ----------------------------------------------------------------------
4
5 Copyright (c) 2006-2019, assimp team
6
7
8 All rights reserved.
9
10 Redistribution and use of this software in source and binary forms,
11 with or without modification, are permitted provided that the
12 following conditions are met:
13
14 * Redistributions of source code must retain the above
15 copyright notice, this list of conditions and the
16 following disclaimer.
17
18 * Redistributions in binary form must reproduce the above
19 copyright notice, this list of conditions and the
20 following disclaimer in the documentation and/or other
21 materials provided with the distribution.
22
23 * Neither the name of the assimp team, nor the names of its
24 contributors may be used to endorse or promote products
25 derived from this software without specific prior
26 written permission of the assimp team.
27
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39
40 ----------------------------------------------------------------------
41 */
42
43 /** @file IFC.cpp
44 * @brief Implementation of the Industry Foundation Classes loader.
45 */
46
47 #ifndef INCLUDED_IFCUTIL_H
48 #define INCLUDED_IFCUTIL_H
49
50 #include "IFCReaderGen_2x3.h"
51 #include "IFCLoader.h"
52 #include "code/Step/STEPFile.h"
53 #include <assimp/mesh.h>
54 #include <assimp/material.h>
55
56 struct aiNode;
57
58 namespace Assimp {
59 namespace IFC {
60
61 typedef double IfcFloat;
62
63 // IfcFloat-precision math data types
64 typedef aiVector2t<IfcFloat> IfcVector2;
65 typedef aiVector3t<IfcFloat> IfcVector3;
66 typedef aiMatrix4x4t<IfcFloat> IfcMatrix4;
67 typedef aiMatrix3x3t<IfcFloat> IfcMatrix3;
68 typedef aiColor4t<IfcFloat> IfcColor4;
69
70
71 // ------------------------------------------------------------------------------------------------
72 // Helper for std::for_each to delete all heap-allocated items in a container
73 // ------------------------------------------------------------------------------------------------
74 template<typename T>
75 struct delete_fun {
operatordelete_fun76 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 // ------------------------------------------------------------------------------------------------
86 struct TempMesh {
87 std::vector<IfcVector3> mVerts;
88 std::vector<unsigned int> mVertcnt;
89
90 // utilities
91 aiMesh* ToMesh();
92 void Clear();
93 void Transform(const IfcMatrix4& mat);
94 IfcVector3 Center() const;
95 void Append(const TempMesh& other);
96 bool IsEmpty() const;
97 void RemoveAdjacentDuplicates();
98 void RemoveDegenerates();
99 void FixupFaceOrientation();
100 static IfcVector3 ComputePolygonNormal(const IfcVector3* vtcs, size_t cnt, bool normalize = true);
101 IfcVector3 ComputeLastPolygonNormal(bool normalize = true) const;
102 void ComputePolygonNormals(std::vector<IfcVector3>& normals, bool normalize = true, size_t ofs = 0) const;
103 void Swap(TempMesh& other);
104 };
105
106 inline
IsEmpty()107 bool TempMesh::IsEmpty() const {
108 return mVerts.empty() && mVertcnt.empty();
109 }
110
111
112 // ------------------------------------------------------------------------------------------------
113 // Temporary representation of an opening in a wall or a floor
114 // ------------------------------------------------------------------------------------------------
115 struct TempOpening
116 {
117 const IFC::Schema_2x3::IfcSolidModel *solid;
118 IfcVector3 extrusionDir;
119
120 std::shared_ptr<TempMesh> profileMesh;
121 std::shared_ptr<TempMesh> profileMesh2D;
122
123 // list of points generated for this opening. This is used to
124 // create connections between two opposing holes created
125 // from a single opening instance (two because walls tend to
126 // have two sides). If !empty(), the other side of the wall
127 // has already been processed.
128 std::vector<IfcVector3> wallPoints;
129
130 // ------------------------------------------------------------------------------
TempOpeningTempOpening131 TempOpening()
132 : solid()
133 , extrusionDir()
134 , profileMesh()
135 {
136 }
137
138 // ------------------------------------------------------------------------------
TempOpeningTempOpening139 TempOpening(const IFC::Schema_2x3::IfcSolidModel* solid,IfcVector3 extrusionDir,
140 std::shared_ptr<TempMesh> profileMesh,
141 std::shared_ptr<TempMesh> profileMesh2D)
142 : solid(solid)
143 , extrusionDir(extrusionDir)
144 , profileMesh(profileMesh)
145 , profileMesh2D(profileMesh2D)
146 {
147 }
148
149 // ------------------------------------------------------------------------------
150 void Transform(const IfcMatrix4& mat); // defined later since TempMesh is not complete yet
151
152
153
154 // ------------------------------------------------------------------------------
155 // Helper to sort openings by distance from a given base point
156 struct DistanceSorter {
157
DistanceSorterTempOpening::DistanceSorter158 DistanceSorter(const IfcVector3& base) : base(base) {}
159
operatorTempOpening::DistanceSorter160 bool operator () (const TempOpening& a, const TempOpening& b) const {
161 return (a.profileMesh->Center()-base).SquareLength() < (b.profileMesh->Center()-base).SquareLength();
162 }
163
164 IfcVector3 base;
165 };
166 };
167
168
169 // ------------------------------------------------------------------------------------------------
170 // Intermediate data storage during conversion. Keeps everything and a bit more.
171 // ------------------------------------------------------------------------------------------------
172 struct ConversionData
173 {
ConversionDataConversionData174 ConversionData(const STEP::DB& db, const IFC::Schema_2x3::IfcProject& proj, aiScene* out,const IFCImporter::Settings& settings)
175 : len_scale(1.0)
176 , angle_scale(-1.0)
177 , db(db)
178 , proj(proj)
179 , out(out)
180 , settings(settings)
181 , apply_openings()
182 , collect_openings()
183 {}
184
~ConversionDataConversionData185 ~ConversionData() {
186 std::for_each(meshes.begin(),meshes.end(),delete_fun<aiMesh>());
187 std::for_each(materials.begin(),materials.end(),delete_fun<aiMaterial>());
188 }
189
190 IfcFloat len_scale, angle_scale;
191 bool plane_angle_in_radians;
192
193 const STEP::DB& db;
194 const IFC::Schema_2x3::IfcProject& proj;
195 aiScene* out;
196
197 IfcMatrix4 wcs;
198 std::vector<aiMesh*> meshes;
199 std::vector<aiMaterial*> materials;
200
201 struct MeshCacheIndex {
202 const IFC::Schema_2x3::IfcRepresentationItem* item; unsigned int matindex;
MeshCacheIndexConversionData::MeshCacheIndex203 MeshCacheIndex() : item(NULL), matindex(0) { }
MeshCacheIndexConversionData::MeshCacheIndex204 MeshCacheIndex(const IFC::Schema_2x3::IfcRepresentationItem* i, unsigned int mi) : item(i), matindex(mi) { }
205 bool operator == (const MeshCacheIndex& o) const { return item == o.item && matindex == o.matindex; }
206 bool operator < (const MeshCacheIndex& o) const { return item < o.item || (item == o.item && matindex < o.matindex); }
207 };
208 typedef std::map<MeshCacheIndex, std::set<unsigned int> > MeshCache;
209 MeshCache cached_meshes;
210
211 typedef std::map<const IFC::Schema_2x3::IfcSurfaceStyle*, unsigned int> MaterialCache;
212 MaterialCache cached_materials;
213
214 const IFCImporter::Settings& settings;
215
216 // Intermediate arrays used to resolve openings in walls: only one of them
217 // can be given at a time. apply_openings if present if the current element
218 // is a wall and needs its openings to be poured into its geometry while
219 // collect_openings is present only if the current element is an
220 // IfcOpeningElement, for which all the geometry needs to be preserved
221 // for later processing by a parent, which is a wall.
222 std::vector<TempOpening>* apply_openings;
223 std::vector<TempOpening>* collect_openings;
224
225 std::set<uint64_t> already_processed;
226 };
227
228
229 // ------------------------------------------------------------------------------------------------
230 // Binary predicate to compare vectors with a given, quadratic epsilon.
231 // ------------------------------------------------------------------------------------------------
232 struct FuzzyVectorCompare {
233
FuzzyVectorCompareFuzzyVectorCompare234 FuzzyVectorCompare(IfcFloat epsilon) : epsilon(epsilon) {}
operatorFuzzyVectorCompare235 bool operator()(const IfcVector3& a, const IfcVector3& b) {
236 return std::abs((a-b).SquareLength()) < epsilon;
237 }
238
239 const IfcFloat epsilon;
240 };
241
242
243 // ------------------------------------------------------------------------------------------------
244 // Ordering predicate to totally order R^2 vectors first by x and then by y
245 // ------------------------------------------------------------------------------------------------
246 struct XYSorter {
247
248 // sort first by X coordinates, then by Y coordinates
operatorXYSorter249 bool operator () (const IfcVector2&a, const IfcVector2& b) const {
250 if (a.x == b.x) {
251 return a.y < b.y;
252 }
253 return a.x < b.x;
254 }
255 };
256
257
258
259 // conversion routines for common IFC entities, implemented in IFCUtil.cpp
260 void ConvertColor(aiColor4D& out, const Schema_2x3::IfcColourRgb& in);
261 void ConvertColor(aiColor4D& out, const Schema_2x3::IfcColourOrFactor& in,ConversionData& conv,const aiColor4D* base);
262 void ConvertCartesianPoint(IfcVector3& out, const Schema_2x3::IfcCartesianPoint& in);
263 void ConvertDirection(IfcVector3& out, const Schema_2x3::IfcDirection& in);
264 void ConvertVector(IfcVector3& out, const Schema_2x3::IfcVector& in);
265 void AssignMatrixAxes(IfcMatrix4& out, const IfcVector3& x, const IfcVector3& y, const IfcVector3& z);
266 void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement3D& in);
267 void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement2D& in);
268 void ConvertAxisPlacement(IfcVector3& axis, IfcVector3& pos, const IFC::Schema_2x3::IfcAxis1Placement& in);
269 void ConvertAxisPlacement(IfcMatrix4& out, const Schema_2x3::IfcAxis2Placement& in, ConversionData& conv);
270 void ConvertTransformOperator(IfcMatrix4& out, const Schema_2x3::IfcCartesianTransformationOperator& op);
271 bool IsTrue(const Assimp::STEP::EXPRESS::BOOLEAN& in);
272 IfcFloat ConvertSIPrefix(const std::string& prefix);
273
274
275 // IFCProfile.cpp
276 bool ProcessProfile(const Schema_2x3::IfcProfileDef& prof, TempMesh& meshout, ConversionData& conv);
277 bool ProcessCurve(const Schema_2x3::IfcCurve& curve, TempMesh& meshout, ConversionData& conv);
278
279 // IFCMaterial.cpp
280 unsigned int ProcessMaterials(uint64_t id, unsigned int prevMatId, ConversionData& conv, bool forceDefaultMat);
281
282 // IFCGeometry.cpp
283 IfcMatrix3 DerivePlaneCoordinateSpace(const TempMesh& curmesh, bool& ok, IfcVector3& norOut);
284 bool ProcessRepresentationItem(const Schema_2x3::IfcRepresentationItem& item, unsigned int matid, std::set<unsigned int>& mesh_indices, ConversionData& conv);
285 void AssignAddedMeshes(std::set<unsigned int>& mesh_indices,aiNode* nd,ConversionData& /*conv*/);
286
287 void ProcessSweptAreaSolid(const Schema_2x3::IfcSweptAreaSolid& swept, TempMesh& meshout,
288 ConversionData& conv);
289
290 void ProcessExtrudedAreaSolid(const Schema_2x3::IfcExtrudedAreaSolid& solid, TempMesh& result,
291 ConversionData& conv, bool collect_openings);
292
293 // IFCBoolean.cpp
294
295 void ProcessBoolean(const Schema_2x3::IfcBooleanResult& boolean, TempMesh& result, ConversionData& conv);
296 void ProcessBooleanHalfSpaceDifference(const Schema_2x3::IfcHalfSpaceSolid* hs, TempMesh& result,
297 const TempMesh& first_operand,
298 ConversionData& conv);
299
300 void ProcessPolygonalBoundedBooleanHalfSpaceDifference(const Schema_2x3::IfcPolygonalBoundedHalfSpace* hs, TempMesh& result,
301 const TempMesh& first_operand,
302 ConversionData& conv);
303 void ProcessBooleanExtrudedAreaSolidDifference(const Schema_2x3::IfcExtrudedAreaSolid* as, TempMesh& result,
304 const TempMesh& first_operand,
305 ConversionData& conv);
306
307
308 // IFCOpenings.cpp
309
310 bool GenerateOpenings(std::vector<TempOpening>& openings,
311 const std::vector<IfcVector3>& nors,
312 TempMesh& curmesh,
313 bool check_intersection,
314 bool generate_connection_geometry,
315 const IfcVector3& wall_extrusion_axis = IfcVector3(0,1,0));
316
317
318
319 // IFCCurve.cpp
320
321 // ------------------------------------------------------------------------------------------------
322 // Custom exception for use by members of the Curve class
323 // ------------------------------------------------------------------------------------------------
324 class CurveError {
325 public:
CurveError(const std::string & s)326 CurveError(const std::string& s)
327 : mStr(s) {
328 // empty
329 }
330
331 std::string mStr;
332 };
333
334 // ------------------------------------------------------------------------------------------------
335 // Temporary representation for an arbitrary sub-class of IfcCurve. Used to sample the curves
336 // to obtain a list of line segments.
337 // ------------------------------------------------------------------------------------------------
338 class Curve {
339 protected:
Curve(const Schema_2x3::IfcCurve & base_entity,ConversionData & conv)340 Curve(const Schema_2x3::IfcCurve& base_entity, ConversionData& conv)
341 : base_entity(base_entity)
342 , conv(conv) {
343 // empty
344 }
345
346 public:
347 typedef std::pair<IfcFloat, IfcFloat> ParamRange;
348
~Curve()349 virtual ~Curve() {}
350
351
352 // check if a curve is closed
353 virtual bool IsClosed() const = 0;
354
355 // evaluate the curve at the given parametric position
356 virtual IfcVector3 Eval(IfcFloat p) const = 0;
357
358 // try to match a point on the curve to a given parameter
359 // for self-intersecting curves, the result is not ambiguous and
360 // it is undefined which parameter is returned.
361 virtual bool ReverseEval(const IfcVector3& val, IfcFloat& paramOut) const;
362
363 // get the range of the curve (both inclusive).
364 // +inf and -inf are valid return values, the curve is not bounded in such a case.
365 virtual std::pair<IfcFloat,IfcFloat> GetParametricRange() const = 0;
366 IfcFloat GetParametricRangeDelta() const;
367
368 // estimate the number of sample points that this curve will require
369 virtual size_t EstimateSampleCount(IfcFloat start,IfcFloat end) const;
370
371 // intelligently sample the curve based on the current settings
372 // and append the result to the mesh
373 virtual void SampleDiscrete(TempMesh& out,IfcFloat start,IfcFloat end) const;
374
375 #ifdef ASSIMP_BUILD_DEBUG
376 // check if a particular parameter value lies within the well-defined range
377 bool InRange(IfcFloat) const;
378 #endif
379 static Curve* Convert(const IFC::Schema_2x3::IfcCurve&,ConversionData& conv);
380
381 protected:
382 const Schema_2x3::IfcCurve& base_entity;
383 ConversionData& conv;
384 };
385
386
387 // --------------------------------------------------------------------------------
388 // A BoundedCurve always holds the invariant that GetParametricRange()
389 // never returns infinite values.
390 // --------------------------------------------------------------------------------
391 class BoundedCurve : public Curve {
392 public:
BoundedCurve(const Schema_2x3::IfcBoundedCurve & entity,ConversionData & conv)393 BoundedCurve(const Schema_2x3::IfcBoundedCurve& entity, ConversionData& conv)
394 : Curve(entity,conv)
395 {}
396
397 public:
398
399 bool IsClosed() const;
400
401 public:
402
403 // sample the entire curve
404 void SampleDiscrete(TempMesh& out) const;
405 using Curve::SampleDiscrete;
406 };
407
408 // IfcProfile.cpp
409 bool ProcessCurve(const Schema_2x3::IfcCurve& curve, TempMesh& meshout, ConversionData& conv);
410 }
411 }
412
413 #endif
414