vrshoot

annotate libs/assimp/IFCCurve.cpp @ 0:b2f14e535253

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 01 Feb 2014 19:58:19 +0200
parents
children
rev   line source
nuclear@0 1 /*
nuclear@0 2 Open Asset Import Library (assimp)
nuclear@0 3 ----------------------------------------------------------------------
nuclear@0 4
nuclear@0 5 Copyright (c) 2006-2012, assimp team
nuclear@0 6 All rights reserved.
nuclear@0 7
nuclear@0 8 Redistribution and use of this software in source and binary forms,
nuclear@0 9 with or without modification, are permitted provided that the
nuclear@0 10 following conditions are met:
nuclear@0 11
nuclear@0 12 * Redistributions of source code must retain the above
nuclear@0 13 copyright notice, this list of conditions and the
nuclear@0 14 following disclaimer.
nuclear@0 15
nuclear@0 16 * Redistributions in binary form must reproduce the above
nuclear@0 17 copyright notice, this list of conditions and the
nuclear@0 18 following disclaimer in the documentation and/or other
nuclear@0 19 materials provided with the distribution.
nuclear@0 20
nuclear@0 21 * Neither the name of the assimp team, nor the names of its
nuclear@0 22 contributors may be used to endorse or promote products
nuclear@0 23 derived from this software without specific prior
nuclear@0 24 written permission of the assimp team.
nuclear@0 25
nuclear@0 26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
nuclear@0 27 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
nuclear@0 28 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
nuclear@0 29 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
nuclear@0 30 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
nuclear@0 31 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
nuclear@0 32 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
nuclear@0 33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
nuclear@0 34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
nuclear@0 35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
nuclear@0 36 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
nuclear@0 37
nuclear@0 38 ----------------------------------------------------------------------
nuclear@0 39 */
nuclear@0 40
nuclear@0 41 /** @file IFCProfile.cpp
nuclear@0 42 * @brief Read profile and curves entities from IFC files
nuclear@0 43 */
nuclear@0 44
nuclear@0 45 #include "AssimpPCH.h"
nuclear@0 46
nuclear@0 47 #ifndef ASSIMP_BUILD_NO_IFC_IMPORTER
nuclear@0 48 #include "IFCUtil.h"
nuclear@0 49
nuclear@0 50 namespace Assimp {
nuclear@0 51 namespace IFC {
nuclear@0 52 namespace {
nuclear@0 53
nuclear@0 54
nuclear@0 55 // --------------------------------------------------------------------------------
nuclear@0 56 // Conic is the base class for Circle and Ellipse
nuclear@0 57 // --------------------------------------------------------------------------------
nuclear@0 58 class Conic : public Curve
nuclear@0 59 {
nuclear@0 60
nuclear@0 61 public:
nuclear@0 62
nuclear@0 63 // --------------------------------------------------
nuclear@0 64 Conic(const IfcConic& entity, ConversionData& conv)
nuclear@0 65 : Curve(entity,conv)
nuclear@0 66 {
nuclear@0 67 IfcMatrix4 trafo;
nuclear@0 68 ConvertAxisPlacement(trafo,*entity.Position,conv);
nuclear@0 69
nuclear@0 70 // for convenience, extract the matrix rows
nuclear@0 71 location = IfcVector3(trafo.a4,trafo.b4,trafo.c4);
nuclear@0 72 p[0] = IfcVector3(trafo.a1,trafo.b1,trafo.c1);
nuclear@0 73 p[1] = IfcVector3(trafo.a2,trafo.b2,trafo.c2);
nuclear@0 74 p[2] = IfcVector3(trafo.a3,trafo.b3,trafo.c3);
nuclear@0 75 }
nuclear@0 76
nuclear@0 77 public:
nuclear@0 78
nuclear@0 79 // --------------------------------------------------
nuclear@0 80 bool IsClosed() const {
nuclear@0 81 return true;
nuclear@0 82 }
nuclear@0 83
nuclear@0 84 // --------------------------------------------------
nuclear@0 85 size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const {
nuclear@0 86 ai_assert(InRange(a) && InRange(b));
nuclear@0 87
nuclear@0 88 a *= conv.angle_scale;
nuclear@0 89 b *= conv.angle_scale;
nuclear@0 90
nuclear@0 91 a = fmod(a,static_cast<IfcFloat>( AI_MATH_TWO_PI ));
nuclear@0 92 b = fmod(b,static_cast<IfcFloat>( AI_MATH_TWO_PI ));
nuclear@0 93 const IfcFloat setting = static_cast<IfcFloat>( AI_MATH_PI * conv.settings.conicSamplingAngle / 180.0 );
nuclear@0 94 return static_cast<size_t>( ceil(abs( b-a)) / setting);
nuclear@0 95 }
nuclear@0 96
nuclear@0 97 // --------------------------------------------------
nuclear@0 98 ParamRange GetParametricRange() const {
nuclear@0 99 return std::make_pair(static_cast<IfcFloat>( 0. ), static_cast<IfcFloat>( AI_MATH_TWO_PI / conv.angle_scale ));
nuclear@0 100 }
nuclear@0 101
nuclear@0 102 protected:
nuclear@0 103 IfcVector3 location, p[3];
nuclear@0 104 };
nuclear@0 105
nuclear@0 106
nuclear@0 107 // --------------------------------------------------------------------------------
nuclear@0 108 // Circle
nuclear@0 109 // --------------------------------------------------------------------------------
nuclear@0 110 class Circle : public Conic
nuclear@0 111 {
nuclear@0 112
nuclear@0 113 public:
nuclear@0 114
nuclear@0 115 // --------------------------------------------------
nuclear@0 116 Circle(const IfcCircle& entity, ConversionData& conv)
nuclear@0 117 : Conic(entity,conv)
nuclear@0 118 , entity(entity)
nuclear@0 119 {
nuclear@0 120 }
nuclear@0 121
nuclear@0 122 public:
nuclear@0 123
nuclear@0 124 // --------------------------------------------------
nuclear@0 125 IfcVector3 Eval(IfcFloat u) const {
nuclear@0 126 u = -conv.angle_scale * u;
nuclear@0 127 return location + static_cast<IfcFloat>(entity.Radius)*(static_cast<IfcFloat>(::cos(u))*p[0] +
nuclear@0 128 static_cast<IfcFloat>(::sin(u))*p[1]);
nuclear@0 129 }
nuclear@0 130
nuclear@0 131 private:
nuclear@0 132 const IfcCircle& entity;
nuclear@0 133 };
nuclear@0 134
nuclear@0 135
nuclear@0 136 // --------------------------------------------------------------------------------
nuclear@0 137 // Ellipse
nuclear@0 138 // --------------------------------------------------------------------------------
nuclear@0 139 class Ellipse : public Conic
nuclear@0 140 {
nuclear@0 141
nuclear@0 142 public:
nuclear@0 143
nuclear@0 144 // --------------------------------------------------
nuclear@0 145 Ellipse(const IfcEllipse& entity, ConversionData& conv)
nuclear@0 146 : Conic(entity,conv)
nuclear@0 147 , entity(entity)
nuclear@0 148 {
nuclear@0 149 }
nuclear@0 150
nuclear@0 151 public:
nuclear@0 152
nuclear@0 153 // --------------------------------------------------
nuclear@0 154 IfcVector3 Eval(IfcFloat u) const {
nuclear@0 155 u = -conv.angle_scale * u;
nuclear@0 156 return location + static_cast<IfcFloat>(entity.SemiAxis1)*static_cast<IfcFloat>(::cos(u))*p[0] +
nuclear@0 157 static_cast<IfcFloat>(entity.SemiAxis2)*static_cast<IfcFloat>(::sin(u))*p[1];
nuclear@0 158 }
nuclear@0 159
nuclear@0 160 private:
nuclear@0 161 const IfcEllipse& entity;
nuclear@0 162 };
nuclear@0 163
nuclear@0 164
nuclear@0 165 // --------------------------------------------------------------------------------
nuclear@0 166 // Line
nuclear@0 167 // --------------------------------------------------------------------------------
nuclear@0 168 class Line : public Curve
nuclear@0 169 {
nuclear@0 170
nuclear@0 171 public:
nuclear@0 172
nuclear@0 173 // --------------------------------------------------
nuclear@0 174 Line(const IfcLine& entity, ConversionData& conv)
nuclear@0 175 : Curve(entity,conv)
nuclear@0 176 , entity(entity)
nuclear@0 177 {
nuclear@0 178 ConvertCartesianPoint(p,entity.Pnt);
nuclear@0 179 ConvertVector(v,entity.Dir);
nuclear@0 180 }
nuclear@0 181
nuclear@0 182 public:
nuclear@0 183
nuclear@0 184 // --------------------------------------------------
nuclear@0 185 bool IsClosed() const {
nuclear@0 186 return false;
nuclear@0 187 }
nuclear@0 188
nuclear@0 189 // --------------------------------------------------
nuclear@0 190 IfcVector3 Eval(IfcFloat u) const {
nuclear@0 191 return p + u*v;
nuclear@0 192 }
nuclear@0 193
nuclear@0 194 // --------------------------------------------------
nuclear@0 195 size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const {
nuclear@0 196 ai_assert(InRange(a) && InRange(b));
nuclear@0 197 // two points are always sufficient for a line segment
nuclear@0 198 return a==b ? 1 : 2;
nuclear@0 199 }
nuclear@0 200
nuclear@0 201
nuclear@0 202 // --------------------------------------------------
nuclear@0 203 void SampleDiscrete(TempMesh& out,IfcFloat a, IfcFloat b) const
nuclear@0 204 {
nuclear@0 205 ai_assert(InRange(a) && InRange(b));
nuclear@0 206
nuclear@0 207 if (a == b) {
nuclear@0 208 out.verts.push_back(Eval(a));
nuclear@0 209 return;
nuclear@0 210 }
nuclear@0 211 out.verts.reserve(out.verts.size()+2);
nuclear@0 212 out.verts.push_back(Eval(a));
nuclear@0 213 out.verts.push_back(Eval(b));
nuclear@0 214 }
nuclear@0 215
nuclear@0 216 // --------------------------------------------------
nuclear@0 217 ParamRange GetParametricRange() const {
nuclear@0 218 const IfcFloat inf = std::numeric_limits<IfcFloat>::infinity();
nuclear@0 219
nuclear@0 220 return std::make_pair(-inf,+inf);
nuclear@0 221 }
nuclear@0 222
nuclear@0 223 private:
nuclear@0 224 const IfcLine& entity;
nuclear@0 225 IfcVector3 p,v;
nuclear@0 226 };
nuclear@0 227
nuclear@0 228 // --------------------------------------------------------------------------------
nuclear@0 229 // CompositeCurve joins multiple smaller, bounded curves
nuclear@0 230 // --------------------------------------------------------------------------------
nuclear@0 231 class CompositeCurve : public BoundedCurve
nuclear@0 232 {
nuclear@0 233
nuclear@0 234 typedef std::pair< boost::shared_ptr< BoundedCurve >, bool > CurveEntry;
nuclear@0 235
nuclear@0 236 public:
nuclear@0 237
nuclear@0 238 // --------------------------------------------------
nuclear@0 239 CompositeCurve(const IfcCompositeCurve& entity, ConversionData& conv)
nuclear@0 240 : BoundedCurve(entity,conv)
nuclear@0 241 , entity(entity)
nuclear@0 242 , total()
nuclear@0 243 {
nuclear@0 244 curves.reserve(entity.Segments.size());
nuclear@0 245 BOOST_FOREACH(const IfcCompositeCurveSegment& curveSegment,entity.Segments) {
nuclear@0 246 // according to the specification, this must be a bounded curve
nuclear@0 247 boost::shared_ptr< Curve > cv(Curve::Convert(curveSegment.ParentCurve,conv));
nuclear@0 248 boost::shared_ptr< BoundedCurve > bc = boost::dynamic_pointer_cast<BoundedCurve>(cv);
nuclear@0 249
nuclear@0 250 if (!bc) {
nuclear@0 251 IFCImporter::LogError("expected segment of composite curve to be a bounded curve");
nuclear@0 252 continue;
nuclear@0 253 }
nuclear@0 254
nuclear@0 255 if ( (std::string)curveSegment.Transition != "CONTINUOUS" ) {
nuclear@0 256 IFCImporter::LogDebug("ignoring transition code on composite curve segment, only continuous transitions are supported");
nuclear@0 257 }
nuclear@0 258
nuclear@0 259 curves.push_back( CurveEntry(bc,IsTrue(curveSegment.SameSense)) );
nuclear@0 260 total += bc->GetParametricRangeDelta();
nuclear@0 261 }
nuclear@0 262
nuclear@0 263 if (curves.empty()) {
nuclear@0 264 throw CurveError("empty composite curve");
nuclear@0 265 }
nuclear@0 266 }
nuclear@0 267
nuclear@0 268 public:
nuclear@0 269
nuclear@0 270 // --------------------------------------------------
nuclear@0 271 IfcVector3 Eval(IfcFloat u) const {
nuclear@0 272 if (curves.empty()) {
nuclear@0 273 return IfcVector3();
nuclear@0 274 }
nuclear@0 275
nuclear@0 276 IfcFloat acc = 0;
nuclear@0 277 BOOST_FOREACH(const CurveEntry& entry, curves) {
nuclear@0 278 const ParamRange& range = entry.first->GetParametricRange();
nuclear@0 279 const IfcFloat delta = abs(range.second-range.first);
nuclear@0 280 if (u < acc+delta) {
nuclear@0 281 return entry.first->Eval( entry.second ? (u-acc) + range.first : range.second-(u-acc));
nuclear@0 282 }
nuclear@0 283
nuclear@0 284 acc += delta;
nuclear@0 285 }
nuclear@0 286 // clamp to end
nuclear@0 287 return curves.back().first->Eval(curves.back().first->GetParametricRange().second);
nuclear@0 288 }
nuclear@0 289
nuclear@0 290 // --------------------------------------------------
nuclear@0 291 size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const {
nuclear@0 292 ai_assert(InRange(a) && InRange(b));
nuclear@0 293 size_t cnt = 0;
nuclear@0 294
nuclear@0 295 IfcFloat acc = 0;
nuclear@0 296 BOOST_FOREACH(const CurveEntry& entry, curves) {
nuclear@0 297 const ParamRange& range = entry.first->GetParametricRange();
nuclear@0 298 const IfcFloat delta = abs(range.second-range.first);
nuclear@0 299 if (a <= acc+delta && b >= acc) {
nuclear@0 300 const IfcFloat at = std::max(static_cast<IfcFloat>( 0. ),a-acc), bt = std::min(delta,b-acc);
nuclear@0 301 cnt += entry.first->EstimateSampleCount( entry.second ? at + range.first : range.second - bt, entry.second ? bt + range.first : range.second - at );
nuclear@0 302 }
nuclear@0 303
nuclear@0 304 acc += delta;
nuclear@0 305 }
nuclear@0 306
nuclear@0 307 return cnt;
nuclear@0 308 }
nuclear@0 309
nuclear@0 310 // --------------------------------------------------
nuclear@0 311 void SampleDiscrete(TempMesh& out,IfcFloat a, IfcFloat b) const
nuclear@0 312 {
nuclear@0 313 ai_assert(InRange(a) && InRange(b));
nuclear@0 314
nuclear@0 315 const size_t cnt = EstimateSampleCount(a,b);
nuclear@0 316 out.verts.reserve(out.verts.size() + cnt);
nuclear@0 317
nuclear@0 318 BOOST_FOREACH(const CurveEntry& entry, curves) {
nuclear@0 319 const size_t cnt = out.verts.size();
nuclear@0 320 entry.first->SampleDiscrete(out);
nuclear@0 321
nuclear@0 322 if (!entry.second && cnt != out.verts.size()) {
nuclear@0 323 std::reverse(out.verts.begin()+cnt,out.verts.end());
nuclear@0 324 }
nuclear@0 325 }
nuclear@0 326 }
nuclear@0 327
nuclear@0 328 // --------------------------------------------------
nuclear@0 329 ParamRange GetParametricRange() const {
nuclear@0 330 return std::make_pair(static_cast<IfcFloat>( 0. ),total);
nuclear@0 331 }
nuclear@0 332
nuclear@0 333 private:
nuclear@0 334 const IfcCompositeCurve& entity;
nuclear@0 335 std::vector< CurveEntry > curves;
nuclear@0 336
nuclear@0 337 IfcFloat total;
nuclear@0 338 };
nuclear@0 339
nuclear@0 340
nuclear@0 341 // --------------------------------------------------------------------------------
nuclear@0 342 // TrimmedCurve can be used to trim an unbounded curve to a bounded range
nuclear@0 343 // --------------------------------------------------------------------------------
nuclear@0 344 class TrimmedCurve : public BoundedCurve
nuclear@0 345 {
nuclear@0 346
nuclear@0 347 public:
nuclear@0 348
nuclear@0 349 // --------------------------------------------------
nuclear@0 350 TrimmedCurve(const IfcTrimmedCurve& entity, ConversionData& conv)
nuclear@0 351 : BoundedCurve(entity,conv)
nuclear@0 352 , entity(entity)
nuclear@0 353 , ok()
nuclear@0 354 {
nuclear@0 355 base = boost::shared_ptr<const Curve>(Curve::Convert(entity.BasisCurve,conv));
nuclear@0 356
nuclear@0 357 typedef boost::shared_ptr<const STEP::EXPRESS::DataType> Entry;
nuclear@0 358
nuclear@0 359 // for some reason, trimmed curves can either specify a parametric value
nuclear@0 360 // or a point on the curve, or both. And they can even specify which of the
nuclear@0 361 // two representations they prefer, even though an information invariant
nuclear@0 362 // claims that they must be identical if both are present.
nuclear@0 363 // oh well.
nuclear@0 364 bool have_param = false, have_point = false;
nuclear@0 365 IfcVector3 point;
nuclear@0 366 BOOST_FOREACH(const Entry sel,entity.Trim1) {
nuclear@0 367 if (const EXPRESS::REAL* const r = sel->ToPtr<EXPRESS::REAL>()) {
nuclear@0 368 range.first = *r;
nuclear@0 369 have_param = true;
nuclear@0 370 break;
nuclear@0 371 }
nuclear@0 372 else if (const IfcCartesianPoint* const r = sel->ResolveSelectPtr<IfcCartesianPoint>(conv.db)) {
nuclear@0 373 ConvertCartesianPoint(point,*r);
nuclear@0 374 have_point = true;
nuclear@0 375 }
nuclear@0 376 }
nuclear@0 377 if (!have_param) {
nuclear@0 378 if (!have_point || !base->ReverseEval(point,range.first)) {
nuclear@0 379 throw CurveError("IfcTrimmedCurve: failed to read first trim parameter, ignoring curve");
nuclear@0 380 }
nuclear@0 381 }
nuclear@0 382 have_param = false, have_point = false;
nuclear@0 383 BOOST_FOREACH(const Entry sel,entity.Trim2) {
nuclear@0 384 if (const EXPRESS::REAL* const r = sel->ToPtr<EXPRESS::REAL>()) {
nuclear@0 385 range.second = *r;
nuclear@0 386 have_param = true;
nuclear@0 387 break;
nuclear@0 388 }
nuclear@0 389 else if (const IfcCartesianPoint* const r = sel->ResolveSelectPtr<IfcCartesianPoint>(conv.db)) {
nuclear@0 390 ConvertCartesianPoint(point,*r);
nuclear@0 391 have_point = true;
nuclear@0 392 }
nuclear@0 393 }
nuclear@0 394 if (!have_param) {
nuclear@0 395 if (!have_point || !base->ReverseEval(point,range.second)) {
nuclear@0 396 throw CurveError("IfcTrimmedCurve: failed to read second trim parameter, ignoring curve");
nuclear@0 397 }
nuclear@0 398 }
nuclear@0 399
nuclear@0 400 agree_sense = IsTrue(entity.SenseAgreement);
nuclear@0 401 if( !agree_sense ) {
nuclear@0 402 std::swap(range.first,range.second);
nuclear@0 403 }
nuclear@0 404
nuclear@0 405 // "NOTE In case of a closed curve, it may be necessary to increment t1 or t2
nuclear@0 406 // by the parametric length for consistency with the sense flag."
nuclear@0 407 if (base->IsClosed()) {
nuclear@0 408 if( range.first > range.second ) {
nuclear@0 409 range.second += base->GetParametricRangeDelta();
nuclear@0 410 }
nuclear@0 411 }
nuclear@0 412
nuclear@0 413 maxval = range.second-range.first;
nuclear@0 414 ai_assert(maxval >= 0);
nuclear@0 415 }
nuclear@0 416
nuclear@0 417 public:
nuclear@0 418
nuclear@0 419 // --------------------------------------------------
nuclear@0 420 IfcVector3 Eval(IfcFloat p) const {
nuclear@0 421 ai_assert(InRange(p));
nuclear@0 422 return base->Eval( TrimParam(p) );
nuclear@0 423 }
nuclear@0 424
nuclear@0 425 // --------------------------------------------------
nuclear@0 426 size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const {
nuclear@0 427 ai_assert(InRange(a) && InRange(b));
nuclear@0 428 return base->EstimateSampleCount(TrimParam(a),TrimParam(b));
nuclear@0 429 }
nuclear@0 430
nuclear@0 431 // --------------------------------------------------
nuclear@0 432 void SampleDiscrete(TempMesh& out,IfcFloat a,IfcFloat b) const {
nuclear@0 433 ai_assert(InRange(a) && InRange(b));
nuclear@0 434 return base->SampleDiscrete(out,TrimParam(a),TrimParam(b));
nuclear@0 435 }
nuclear@0 436
nuclear@0 437 // --------------------------------------------------
nuclear@0 438 ParamRange GetParametricRange() const {
nuclear@0 439 return std::make_pair(static_cast<IfcFloat>( 0. ),maxval);
nuclear@0 440 }
nuclear@0 441
nuclear@0 442 private:
nuclear@0 443
nuclear@0 444 // --------------------------------------------------
nuclear@0 445 IfcFloat TrimParam(IfcFloat f) const {
nuclear@0 446 return agree_sense ? f + range.first : range.second - f;
nuclear@0 447 }
nuclear@0 448
nuclear@0 449
nuclear@0 450 private:
nuclear@0 451 const IfcTrimmedCurve& entity;
nuclear@0 452 ParamRange range;
nuclear@0 453 IfcFloat maxval;
nuclear@0 454 bool agree_sense;
nuclear@0 455 bool ok;
nuclear@0 456
nuclear@0 457 boost::shared_ptr<const Curve> base;
nuclear@0 458 };
nuclear@0 459
nuclear@0 460
nuclear@0 461 // --------------------------------------------------------------------------------
nuclear@0 462 // PolyLine is a 'curve' defined by linear interpolation over a set of discrete points
nuclear@0 463 // --------------------------------------------------------------------------------
nuclear@0 464 class PolyLine : public BoundedCurve
nuclear@0 465 {
nuclear@0 466
nuclear@0 467 public:
nuclear@0 468
nuclear@0 469 // --------------------------------------------------
nuclear@0 470 PolyLine(const IfcPolyline& entity, ConversionData& conv)
nuclear@0 471 : BoundedCurve(entity,conv)
nuclear@0 472 , entity(entity)
nuclear@0 473 {
nuclear@0 474 points.reserve(entity.Points.size());
nuclear@0 475
nuclear@0 476 IfcVector3 t;
nuclear@0 477 BOOST_FOREACH(const IfcCartesianPoint& cp, entity.Points) {
nuclear@0 478 ConvertCartesianPoint(t,cp);
nuclear@0 479 points.push_back(t);
nuclear@0 480 }
nuclear@0 481 }
nuclear@0 482
nuclear@0 483 public:
nuclear@0 484
nuclear@0 485 // --------------------------------------------------
nuclear@0 486 IfcVector3 Eval(IfcFloat p) const {
nuclear@0 487 ai_assert(InRange(p));
nuclear@0 488
nuclear@0 489 const size_t b = static_cast<size_t>(floor(p));
nuclear@0 490 if (b == points.size()-1) {
nuclear@0 491 return points.back();
nuclear@0 492 }
nuclear@0 493
nuclear@0 494 const IfcFloat d = p-static_cast<IfcFloat>(b);
nuclear@0 495 return points[b+1] * d + points[b] * (static_cast<IfcFloat>( 1. )-d);
nuclear@0 496 }
nuclear@0 497
nuclear@0 498 // --------------------------------------------------
nuclear@0 499 size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const {
nuclear@0 500 ai_assert(InRange(a) && InRange(b));
nuclear@0 501 return static_cast<size_t>( ceil(b) - floor(a) );
nuclear@0 502 }
nuclear@0 503
nuclear@0 504 // --------------------------------------------------
nuclear@0 505 ParamRange GetParametricRange() const {
nuclear@0 506 return std::make_pair(static_cast<IfcFloat>( 0. ),static_cast<IfcFloat>(points.size()-1));
nuclear@0 507 }
nuclear@0 508
nuclear@0 509 private:
nuclear@0 510 const IfcPolyline& entity;
nuclear@0 511 std::vector<IfcVector3> points;
nuclear@0 512 };
nuclear@0 513
nuclear@0 514
nuclear@0 515 } // anon
nuclear@0 516
nuclear@0 517
nuclear@0 518 // ------------------------------------------------------------------------------------------------
nuclear@0 519 Curve* Curve :: Convert(const IFC::IfcCurve& curve,ConversionData& conv)
nuclear@0 520 {
nuclear@0 521 if(curve.ToPtr<IfcBoundedCurve>()) {
nuclear@0 522 if(const IfcPolyline* c = curve.ToPtr<IfcPolyline>()) {
nuclear@0 523 return new PolyLine(*c,conv);
nuclear@0 524 }
nuclear@0 525 if(const IfcTrimmedCurve* c = curve.ToPtr<IfcTrimmedCurve>()) {
nuclear@0 526 return new TrimmedCurve(*c,conv);
nuclear@0 527 }
nuclear@0 528 if(const IfcCompositeCurve* c = curve.ToPtr<IfcCompositeCurve>()) {
nuclear@0 529 return new CompositeCurve(*c,conv);
nuclear@0 530 }
nuclear@0 531 //if(const IfcBSplineCurve* c = curve.ToPtr<IfcBSplineCurve>()) {
nuclear@0 532 // return new BSplineCurve(*c,conv);
nuclear@0 533 //}
nuclear@0 534 }
nuclear@0 535
nuclear@0 536 if(curve.ToPtr<IfcConic>()) {
nuclear@0 537 if(const IfcCircle* c = curve.ToPtr<IfcCircle>()) {
nuclear@0 538 return new Circle(*c,conv);
nuclear@0 539 }
nuclear@0 540 if(const IfcEllipse* c = curve.ToPtr<IfcEllipse>()) {
nuclear@0 541 return new Ellipse(*c,conv);
nuclear@0 542 }
nuclear@0 543 }
nuclear@0 544
nuclear@0 545 if(const IfcLine* c = curve.ToPtr<IfcLine>()) {
nuclear@0 546 return new Line(*c,conv);
nuclear@0 547 }
nuclear@0 548
nuclear@0 549 // XXX OffsetCurve2D, OffsetCurve3D not currently supported
nuclear@0 550 return NULL;
nuclear@0 551 }
nuclear@0 552
nuclear@0 553 #ifdef _DEBUG
nuclear@0 554 // ------------------------------------------------------------------------------------------------
nuclear@0 555 bool Curve :: InRange(IfcFloat u) const
nuclear@0 556 {
nuclear@0 557 const ParamRange range = GetParametricRange();
nuclear@0 558 if (IsClosed()) {
nuclear@0 559 return true;
nuclear@0 560 //ai_assert(range.first != std::numeric_limits<IfcFloat>::infinity() && range.second != std::numeric_limits<IfcFloat>::infinity());
nuclear@0 561 //u = range.first + fmod(u-range.first,range.second-range.first);
nuclear@0 562 }
nuclear@0 563 const IfcFloat epsilon = 1e-5;
nuclear@0 564 return u - range.first > -epsilon && range.second - u > -epsilon;
nuclear@0 565 }
nuclear@0 566 #endif
nuclear@0 567
nuclear@0 568 // ------------------------------------------------------------------------------------------------
nuclear@0 569 IfcFloat Curve :: GetParametricRangeDelta() const
nuclear@0 570 {
nuclear@0 571 const ParamRange& range = GetParametricRange();
nuclear@0 572 return abs(range.second - range.first);
nuclear@0 573 }
nuclear@0 574
nuclear@0 575 // ------------------------------------------------------------------------------------------------
nuclear@0 576 size_t Curve :: EstimateSampleCount(IfcFloat a, IfcFloat b) const
nuclear@0 577 {
nuclear@0 578 ai_assert(InRange(a) && InRange(b));
nuclear@0 579
nuclear@0 580 // arbitrary default value, deriving classes should supply better suited values
nuclear@0 581 return 16;
nuclear@0 582 }
nuclear@0 583
nuclear@0 584 // ------------------------------------------------------------------------------------------------
nuclear@0 585 IfcFloat RecursiveSearch(const Curve* cv, const IfcVector3& val, IfcFloat a, IfcFloat b, unsigned int samples, IfcFloat threshold, unsigned int recurse = 0, unsigned int max_recurse = 15)
nuclear@0 586 {
nuclear@0 587 ai_assert(samples>1);
nuclear@0 588
nuclear@0 589 const IfcFloat delta = (b-a)/samples, inf = std::numeric_limits<IfcFloat>::infinity();
nuclear@0 590 IfcFloat min_point[2] = {a,b}, min_diff[2] = {inf,inf};
nuclear@0 591 IfcFloat runner = a;
nuclear@0 592
nuclear@0 593 for (unsigned int i = 0; i < samples; ++i, runner += delta) {
nuclear@0 594 const IfcFloat diff = (cv->Eval(runner)-val).SquareLength();
nuclear@0 595 if (diff < min_diff[0]) {
nuclear@0 596 min_diff[1] = min_diff[0];
nuclear@0 597 min_point[1] = min_point[0];
nuclear@0 598
nuclear@0 599 min_diff[0] = diff;
nuclear@0 600 min_point[0] = runner;
nuclear@0 601 }
nuclear@0 602 else if (diff < min_diff[1]) {
nuclear@0 603 min_diff[1] = diff;
nuclear@0 604 min_point[1] = runner;
nuclear@0 605 }
nuclear@0 606 }
nuclear@0 607
nuclear@0 608 ai_assert(min_diff[0] != inf && min_diff[1] != inf);
nuclear@0 609 if ( fabs(a-min_point[0]) < threshold || recurse >= max_recurse) {
nuclear@0 610 return min_point[0];
nuclear@0 611 }
nuclear@0 612
nuclear@0 613 // fix for closed curves to take their wrap-over into account
nuclear@0 614 if (cv->IsClosed() && fabs(min_point[0]-min_point[1]) > cv->GetParametricRangeDelta()*0.5 ) {
nuclear@0 615 const Curve::ParamRange& range = cv->GetParametricRange();
nuclear@0 616 const IfcFloat wrapdiff = (cv->Eval(range.first)-val).SquareLength();
nuclear@0 617
nuclear@0 618 if (wrapdiff < min_diff[0]) {
nuclear@0 619 const IfcFloat t = min_point[0];
nuclear@0 620 min_point[0] = min_point[1] > min_point[0] ? range.first : range.second;
nuclear@0 621 min_point[1] = t;
nuclear@0 622 }
nuclear@0 623 }
nuclear@0 624
nuclear@0 625 return RecursiveSearch(cv,val,min_point[0],min_point[1],samples,threshold,recurse+1,max_recurse);
nuclear@0 626 }
nuclear@0 627
nuclear@0 628 // ------------------------------------------------------------------------------------------------
nuclear@0 629 bool Curve :: ReverseEval(const IfcVector3& val, IfcFloat& paramOut) const
nuclear@0 630 {
nuclear@0 631 // note: the following algorithm is not guaranteed to find the 'right' parameter value
nuclear@0 632 // in all possible cases, but it will always return at least some value so this function
nuclear@0 633 // will never fail in the default implementation.
nuclear@0 634
nuclear@0 635 // XXX derive threshold from curve topology
nuclear@0 636 const IfcFloat threshold = 1e-4f;
nuclear@0 637 const unsigned int samples = 16;
nuclear@0 638
nuclear@0 639 const ParamRange& range = GetParametricRange();
nuclear@0 640 paramOut = RecursiveSearch(this,val,range.first,range.second,samples,threshold);
nuclear@0 641
nuclear@0 642 return true;
nuclear@0 643 }
nuclear@0 644
nuclear@0 645 // ------------------------------------------------------------------------------------------------
nuclear@0 646 void Curve :: SampleDiscrete(TempMesh& out,IfcFloat a, IfcFloat b) const
nuclear@0 647 {
nuclear@0 648 ai_assert(InRange(a) && InRange(b));
nuclear@0 649
nuclear@0 650 const size_t cnt = std::max(static_cast<size_t>(0),EstimateSampleCount(a,b));
nuclear@0 651 out.verts.reserve( out.verts.size() + cnt );
nuclear@0 652
nuclear@0 653 IfcFloat p = a, delta = (b-a)/cnt;
nuclear@0 654 for(size_t i = 0; i < cnt; ++i, p += delta) {
nuclear@0 655 out.verts.push_back(Eval(p));
nuclear@0 656 }
nuclear@0 657 }
nuclear@0 658
nuclear@0 659 // ------------------------------------------------------------------------------------------------
nuclear@0 660 bool BoundedCurve :: IsClosed() const
nuclear@0 661 {
nuclear@0 662 return false;
nuclear@0 663 }
nuclear@0 664
nuclear@0 665 // ------------------------------------------------------------------------------------------------
nuclear@0 666 void BoundedCurve :: SampleDiscrete(TempMesh& out) const
nuclear@0 667 {
nuclear@0 668 const ParamRange& range = GetParametricRange();
nuclear@0 669 ai_assert(range.first != std::numeric_limits<IfcFloat>::infinity() && range.second != std::numeric_limits<IfcFloat>::infinity());
nuclear@0 670
nuclear@0 671 return SampleDiscrete(out,range.first,range.second);
nuclear@0 672 }
nuclear@0 673
nuclear@0 674 } // IFC
nuclear@0 675 } // Assimp
nuclear@0 676
nuclear@0 677 #endif // ASSIMP_BUILD_NO_IFC_IMPORTER