vrshoot
diff 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 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/assimp/IFCCurve.cpp Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,677 @@ 1.4 +/* 1.5 +Open Asset Import Library (assimp) 1.6 +---------------------------------------------------------------------- 1.7 + 1.8 +Copyright (c) 2006-2012, assimp team 1.9 +All rights reserved. 1.10 + 1.11 +Redistribution and use of this software in source and binary forms, 1.12 +with or without modification, are permitted provided that the 1.13 +following conditions are met: 1.14 + 1.15 +* Redistributions of source code must retain the above 1.16 + copyright notice, this list of conditions and the 1.17 + following disclaimer. 1.18 + 1.19 +* Redistributions in binary form must reproduce the above 1.20 + copyright notice, this list of conditions and the 1.21 + following disclaimer in the documentation and/or other 1.22 + materials provided with the distribution. 1.23 + 1.24 +* Neither the name of the assimp team, nor the names of its 1.25 + contributors may be used to endorse or promote products 1.26 + derived from this software without specific prior 1.27 + written permission of the assimp team. 1.28 + 1.29 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.30 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.31 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.32 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.33 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.34 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.35 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.36 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.37 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.38 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.39 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.40 + 1.41 +---------------------------------------------------------------------- 1.42 +*/ 1.43 + 1.44 +/** @file IFCProfile.cpp 1.45 + * @brief Read profile and curves entities from IFC files 1.46 + */ 1.47 + 1.48 +#include "AssimpPCH.h" 1.49 + 1.50 +#ifndef ASSIMP_BUILD_NO_IFC_IMPORTER 1.51 +#include "IFCUtil.h" 1.52 + 1.53 +namespace Assimp { 1.54 + namespace IFC { 1.55 + namespace { 1.56 + 1.57 + 1.58 +// -------------------------------------------------------------------------------- 1.59 +// Conic is the base class for Circle and Ellipse 1.60 +// -------------------------------------------------------------------------------- 1.61 +class Conic : public Curve 1.62 +{ 1.63 + 1.64 +public: 1.65 + 1.66 + // -------------------------------------------------- 1.67 + Conic(const IfcConic& entity, ConversionData& conv) 1.68 + : Curve(entity,conv) 1.69 + { 1.70 + IfcMatrix4 trafo; 1.71 + ConvertAxisPlacement(trafo,*entity.Position,conv); 1.72 + 1.73 + // for convenience, extract the matrix rows 1.74 + location = IfcVector3(trafo.a4,trafo.b4,trafo.c4); 1.75 + p[0] = IfcVector3(trafo.a1,trafo.b1,trafo.c1); 1.76 + p[1] = IfcVector3(trafo.a2,trafo.b2,trafo.c2); 1.77 + p[2] = IfcVector3(trafo.a3,trafo.b3,trafo.c3); 1.78 + } 1.79 + 1.80 +public: 1.81 + 1.82 + // -------------------------------------------------- 1.83 + bool IsClosed() const { 1.84 + return true; 1.85 + } 1.86 + 1.87 + // -------------------------------------------------- 1.88 + size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const { 1.89 + ai_assert(InRange(a) && InRange(b)); 1.90 + 1.91 + a *= conv.angle_scale; 1.92 + b *= conv.angle_scale; 1.93 + 1.94 + a = fmod(a,static_cast<IfcFloat>( AI_MATH_TWO_PI )); 1.95 + b = fmod(b,static_cast<IfcFloat>( AI_MATH_TWO_PI )); 1.96 + const IfcFloat setting = static_cast<IfcFloat>( AI_MATH_PI * conv.settings.conicSamplingAngle / 180.0 ); 1.97 + return static_cast<size_t>( ceil(abs( b-a)) / setting); 1.98 + } 1.99 + 1.100 + // -------------------------------------------------- 1.101 + ParamRange GetParametricRange() const { 1.102 + return std::make_pair(static_cast<IfcFloat>( 0. ), static_cast<IfcFloat>( AI_MATH_TWO_PI / conv.angle_scale )); 1.103 + } 1.104 + 1.105 +protected: 1.106 + IfcVector3 location, p[3]; 1.107 +}; 1.108 + 1.109 + 1.110 +// -------------------------------------------------------------------------------- 1.111 +// Circle 1.112 +// -------------------------------------------------------------------------------- 1.113 +class Circle : public Conic 1.114 +{ 1.115 + 1.116 +public: 1.117 + 1.118 + // -------------------------------------------------- 1.119 + Circle(const IfcCircle& entity, ConversionData& conv) 1.120 + : Conic(entity,conv) 1.121 + , entity(entity) 1.122 + { 1.123 + } 1.124 + 1.125 +public: 1.126 + 1.127 + // -------------------------------------------------- 1.128 + IfcVector3 Eval(IfcFloat u) const { 1.129 + u = -conv.angle_scale * u; 1.130 + return location + static_cast<IfcFloat>(entity.Radius)*(static_cast<IfcFloat>(::cos(u))*p[0] + 1.131 + static_cast<IfcFloat>(::sin(u))*p[1]); 1.132 + } 1.133 + 1.134 +private: 1.135 + const IfcCircle& entity; 1.136 +}; 1.137 + 1.138 + 1.139 +// -------------------------------------------------------------------------------- 1.140 +// Ellipse 1.141 +// -------------------------------------------------------------------------------- 1.142 +class Ellipse : public Conic 1.143 +{ 1.144 + 1.145 +public: 1.146 + 1.147 + // -------------------------------------------------- 1.148 + Ellipse(const IfcEllipse& entity, ConversionData& conv) 1.149 + : Conic(entity,conv) 1.150 + , entity(entity) 1.151 + { 1.152 + } 1.153 + 1.154 +public: 1.155 + 1.156 + // -------------------------------------------------- 1.157 + IfcVector3 Eval(IfcFloat u) const { 1.158 + u = -conv.angle_scale * u; 1.159 + return location + static_cast<IfcFloat>(entity.SemiAxis1)*static_cast<IfcFloat>(::cos(u))*p[0] + 1.160 + static_cast<IfcFloat>(entity.SemiAxis2)*static_cast<IfcFloat>(::sin(u))*p[1]; 1.161 + } 1.162 + 1.163 +private: 1.164 + const IfcEllipse& entity; 1.165 +}; 1.166 + 1.167 + 1.168 +// -------------------------------------------------------------------------------- 1.169 +// Line 1.170 +// -------------------------------------------------------------------------------- 1.171 +class Line : public Curve 1.172 +{ 1.173 + 1.174 +public: 1.175 + 1.176 + // -------------------------------------------------- 1.177 + Line(const IfcLine& entity, ConversionData& conv) 1.178 + : Curve(entity,conv) 1.179 + , entity(entity) 1.180 + { 1.181 + ConvertCartesianPoint(p,entity.Pnt); 1.182 + ConvertVector(v,entity.Dir); 1.183 + } 1.184 + 1.185 +public: 1.186 + 1.187 + // -------------------------------------------------- 1.188 + bool IsClosed() const { 1.189 + return false; 1.190 + } 1.191 + 1.192 + // -------------------------------------------------- 1.193 + IfcVector3 Eval(IfcFloat u) const { 1.194 + return p + u*v; 1.195 + } 1.196 + 1.197 + // -------------------------------------------------- 1.198 + size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const { 1.199 + ai_assert(InRange(a) && InRange(b)); 1.200 + // two points are always sufficient for a line segment 1.201 + return a==b ? 1 : 2; 1.202 + } 1.203 + 1.204 + 1.205 + // -------------------------------------------------- 1.206 + void SampleDiscrete(TempMesh& out,IfcFloat a, IfcFloat b) const 1.207 + { 1.208 + ai_assert(InRange(a) && InRange(b)); 1.209 + 1.210 + if (a == b) { 1.211 + out.verts.push_back(Eval(a)); 1.212 + return; 1.213 + } 1.214 + out.verts.reserve(out.verts.size()+2); 1.215 + out.verts.push_back(Eval(a)); 1.216 + out.verts.push_back(Eval(b)); 1.217 + } 1.218 + 1.219 + // -------------------------------------------------- 1.220 + ParamRange GetParametricRange() const { 1.221 + const IfcFloat inf = std::numeric_limits<IfcFloat>::infinity(); 1.222 + 1.223 + return std::make_pair(-inf,+inf); 1.224 + } 1.225 + 1.226 +private: 1.227 + const IfcLine& entity; 1.228 + IfcVector3 p,v; 1.229 +}; 1.230 + 1.231 +// -------------------------------------------------------------------------------- 1.232 +// CompositeCurve joins multiple smaller, bounded curves 1.233 +// -------------------------------------------------------------------------------- 1.234 +class CompositeCurve : public BoundedCurve 1.235 +{ 1.236 + 1.237 + typedef std::pair< boost::shared_ptr< BoundedCurve >, bool > CurveEntry; 1.238 + 1.239 +public: 1.240 + 1.241 + // -------------------------------------------------- 1.242 + CompositeCurve(const IfcCompositeCurve& entity, ConversionData& conv) 1.243 + : BoundedCurve(entity,conv) 1.244 + , entity(entity) 1.245 + , total() 1.246 + { 1.247 + curves.reserve(entity.Segments.size()); 1.248 + BOOST_FOREACH(const IfcCompositeCurveSegment& curveSegment,entity.Segments) { 1.249 + // according to the specification, this must be a bounded curve 1.250 + boost::shared_ptr< Curve > cv(Curve::Convert(curveSegment.ParentCurve,conv)); 1.251 + boost::shared_ptr< BoundedCurve > bc = boost::dynamic_pointer_cast<BoundedCurve>(cv); 1.252 + 1.253 + if (!bc) { 1.254 + IFCImporter::LogError("expected segment of composite curve to be a bounded curve"); 1.255 + continue; 1.256 + } 1.257 + 1.258 + if ( (std::string)curveSegment.Transition != "CONTINUOUS" ) { 1.259 + IFCImporter::LogDebug("ignoring transition code on composite curve segment, only continuous transitions are supported"); 1.260 + } 1.261 + 1.262 + curves.push_back( CurveEntry(bc,IsTrue(curveSegment.SameSense)) ); 1.263 + total += bc->GetParametricRangeDelta(); 1.264 + } 1.265 + 1.266 + if (curves.empty()) { 1.267 + throw CurveError("empty composite curve"); 1.268 + } 1.269 + } 1.270 + 1.271 +public: 1.272 + 1.273 + // -------------------------------------------------- 1.274 + IfcVector3 Eval(IfcFloat u) const { 1.275 + if (curves.empty()) { 1.276 + return IfcVector3(); 1.277 + } 1.278 + 1.279 + IfcFloat acc = 0; 1.280 + BOOST_FOREACH(const CurveEntry& entry, curves) { 1.281 + const ParamRange& range = entry.first->GetParametricRange(); 1.282 + const IfcFloat delta = abs(range.second-range.first); 1.283 + if (u < acc+delta) { 1.284 + return entry.first->Eval( entry.second ? (u-acc) + range.first : range.second-(u-acc)); 1.285 + } 1.286 + 1.287 + acc += delta; 1.288 + } 1.289 + // clamp to end 1.290 + return curves.back().first->Eval(curves.back().first->GetParametricRange().second); 1.291 + } 1.292 + 1.293 + // -------------------------------------------------- 1.294 + size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const { 1.295 + ai_assert(InRange(a) && InRange(b)); 1.296 + size_t cnt = 0; 1.297 + 1.298 + IfcFloat acc = 0; 1.299 + BOOST_FOREACH(const CurveEntry& entry, curves) { 1.300 + const ParamRange& range = entry.first->GetParametricRange(); 1.301 + const IfcFloat delta = abs(range.second-range.first); 1.302 + if (a <= acc+delta && b >= acc) { 1.303 + const IfcFloat at = std::max(static_cast<IfcFloat>( 0. ),a-acc), bt = std::min(delta,b-acc); 1.304 + cnt += entry.first->EstimateSampleCount( entry.second ? at + range.first : range.second - bt, entry.second ? bt + range.first : range.second - at ); 1.305 + } 1.306 + 1.307 + acc += delta; 1.308 + } 1.309 + 1.310 + return cnt; 1.311 + } 1.312 + 1.313 + // -------------------------------------------------- 1.314 + void SampleDiscrete(TempMesh& out,IfcFloat a, IfcFloat b) const 1.315 + { 1.316 + ai_assert(InRange(a) && InRange(b)); 1.317 + 1.318 + const size_t cnt = EstimateSampleCount(a,b); 1.319 + out.verts.reserve(out.verts.size() + cnt); 1.320 + 1.321 + BOOST_FOREACH(const CurveEntry& entry, curves) { 1.322 + const size_t cnt = out.verts.size(); 1.323 + entry.first->SampleDiscrete(out); 1.324 + 1.325 + if (!entry.second && cnt != out.verts.size()) { 1.326 + std::reverse(out.verts.begin()+cnt,out.verts.end()); 1.327 + } 1.328 + } 1.329 + } 1.330 + 1.331 + // -------------------------------------------------- 1.332 + ParamRange GetParametricRange() const { 1.333 + return std::make_pair(static_cast<IfcFloat>( 0. ),total); 1.334 + } 1.335 + 1.336 +private: 1.337 + const IfcCompositeCurve& entity; 1.338 + std::vector< CurveEntry > curves; 1.339 + 1.340 + IfcFloat total; 1.341 +}; 1.342 + 1.343 + 1.344 +// -------------------------------------------------------------------------------- 1.345 +// TrimmedCurve can be used to trim an unbounded curve to a bounded range 1.346 +// -------------------------------------------------------------------------------- 1.347 +class TrimmedCurve : public BoundedCurve 1.348 +{ 1.349 + 1.350 +public: 1.351 + 1.352 + // -------------------------------------------------- 1.353 + TrimmedCurve(const IfcTrimmedCurve& entity, ConversionData& conv) 1.354 + : BoundedCurve(entity,conv) 1.355 + , entity(entity) 1.356 + , ok() 1.357 + { 1.358 + base = boost::shared_ptr<const Curve>(Curve::Convert(entity.BasisCurve,conv)); 1.359 + 1.360 + typedef boost::shared_ptr<const STEP::EXPRESS::DataType> Entry; 1.361 + 1.362 + // for some reason, trimmed curves can either specify a parametric value 1.363 + // or a point on the curve, or both. And they can even specify which of the 1.364 + // two representations they prefer, even though an information invariant 1.365 + // claims that they must be identical if both are present. 1.366 + // oh well. 1.367 + bool have_param = false, have_point = false; 1.368 + IfcVector3 point; 1.369 + BOOST_FOREACH(const Entry sel,entity.Trim1) { 1.370 + if (const EXPRESS::REAL* const r = sel->ToPtr<EXPRESS::REAL>()) { 1.371 + range.first = *r; 1.372 + have_param = true; 1.373 + break; 1.374 + } 1.375 + else if (const IfcCartesianPoint* const r = sel->ResolveSelectPtr<IfcCartesianPoint>(conv.db)) { 1.376 + ConvertCartesianPoint(point,*r); 1.377 + have_point = true; 1.378 + } 1.379 + } 1.380 + if (!have_param) { 1.381 + if (!have_point || !base->ReverseEval(point,range.first)) { 1.382 + throw CurveError("IfcTrimmedCurve: failed to read first trim parameter, ignoring curve"); 1.383 + } 1.384 + } 1.385 + have_param = false, have_point = false; 1.386 + BOOST_FOREACH(const Entry sel,entity.Trim2) { 1.387 + if (const EXPRESS::REAL* const r = sel->ToPtr<EXPRESS::REAL>()) { 1.388 + range.second = *r; 1.389 + have_param = true; 1.390 + break; 1.391 + } 1.392 + else if (const IfcCartesianPoint* const r = sel->ResolveSelectPtr<IfcCartesianPoint>(conv.db)) { 1.393 + ConvertCartesianPoint(point,*r); 1.394 + have_point = true; 1.395 + } 1.396 + } 1.397 + if (!have_param) { 1.398 + if (!have_point || !base->ReverseEval(point,range.second)) { 1.399 + throw CurveError("IfcTrimmedCurve: failed to read second trim parameter, ignoring curve"); 1.400 + } 1.401 + } 1.402 + 1.403 + agree_sense = IsTrue(entity.SenseAgreement); 1.404 + if( !agree_sense ) { 1.405 + std::swap(range.first,range.second); 1.406 + } 1.407 + 1.408 + // "NOTE In case of a closed curve, it may be necessary to increment t1 or t2 1.409 + // by the parametric length for consistency with the sense flag." 1.410 + if (base->IsClosed()) { 1.411 + if( range.first > range.second ) { 1.412 + range.second += base->GetParametricRangeDelta(); 1.413 + } 1.414 + } 1.415 + 1.416 + maxval = range.second-range.first; 1.417 + ai_assert(maxval >= 0); 1.418 + } 1.419 + 1.420 +public: 1.421 + 1.422 + // -------------------------------------------------- 1.423 + IfcVector3 Eval(IfcFloat p) const { 1.424 + ai_assert(InRange(p)); 1.425 + return base->Eval( TrimParam(p) ); 1.426 + } 1.427 + 1.428 + // -------------------------------------------------- 1.429 + size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const { 1.430 + ai_assert(InRange(a) && InRange(b)); 1.431 + return base->EstimateSampleCount(TrimParam(a),TrimParam(b)); 1.432 + } 1.433 + 1.434 + // -------------------------------------------------- 1.435 + void SampleDiscrete(TempMesh& out,IfcFloat a,IfcFloat b) const { 1.436 + ai_assert(InRange(a) && InRange(b)); 1.437 + return base->SampleDiscrete(out,TrimParam(a),TrimParam(b)); 1.438 + } 1.439 + 1.440 + // -------------------------------------------------- 1.441 + ParamRange GetParametricRange() const { 1.442 + return std::make_pair(static_cast<IfcFloat>( 0. ),maxval); 1.443 + } 1.444 + 1.445 +private: 1.446 + 1.447 + // -------------------------------------------------- 1.448 + IfcFloat TrimParam(IfcFloat f) const { 1.449 + return agree_sense ? f + range.first : range.second - f; 1.450 + } 1.451 + 1.452 + 1.453 +private: 1.454 + const IfcTrimmedCurve& entity; 1.455 + ParamRange range; 1.456 + IfcFloat maxval; 1.457 + bool agree_sense; 1.458 + bool ok; 1.459 + 1.460 + boost::shared_ptr<const Curve> base; 1.461 +}; 1.462 + 1.463 + 1.464 +// -------------------------------------------------------------------------------- 1.465 +// PolyLine is a 'curve' defined by linear interpolation over a set of discrete points 1.466 +// -------------------------------------------------------------------------------- 1.467 +class PolyLine : public BoundedCurve 1.468 +{ 1.469 + 1.470 +public: 1.471 + 1.472 + // -------------------------------------------------- 1.473 + PolyLine(const IfcPolyline& entity, ConversionData& conv) 1.474 + : BoundedCurve(entity,conv) 1.475 + , entity(entity) 1.476 + { 1.477 + points.reserve(entity.Points.size()); 1.478 + 1.479 + IfcVector3 t; 1.480 + BOOST_FOREACH(const IfcCartesianPoint& cp, entity.Points) { 1.481 + ConvertCartesianPoint(t,cp); 1.482 + points.push_back(t); 1.483 + } 1.484 + } 1.485 + 1.486 +public: 1.487 + 1.488 + // -------------------------------------------------- 1.489 + IfcVector3 Eval(IfcFloat p) const { 1.490 + ai_assert(InRange(p)); 1.491 + 1.492 + const size_t b = static_cast<size_t>(floor(p)); 1.493 + if (b == points.size()-1) { 1.494 + return points.back(); 1.495 + } 1.496 + 1.497 + const IfcFloat d = p-static_cast<IfcFloat>(b); 1.498 + return points[b+1] * d + points[b] * (static_cast<IfcFloat>( 1. )-d); 1.499 + } 1.500 + 1.501 + // -------------------------------------------------- 1.502 + size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const { 1.503 + ai_assert(InRange(a) && InRange(b)); 1.504 + return static_cast<size_t>( ceil(b) - floor(a) ); 1.505 + } 1.506 + 1.507 + // -------------------------------------------------- 1.508 + ParamRange GetParametricRange() const { 1.509 + return std::make_pair(static_cast<IfcFloat>( 0. ),static_cast<IfcFloat>(points.size()-1)); 1.510 + } 1.511 + 1.512 +private: 1.513 + const IfcPolyline& entity; 1.514 + std::vector<IfcVector3> points; 1.515 +}; 1.516 + 1.517 + 1.518 +} // anon 1.519 + 1.520 + 1.521 +// ------------------------------------------------------------------------------------------------ 1.522 +Curve* Curve :: Convert(const IFC::IfcCurve& curve,ConversionData& conv) 1.523 +{ 1.524 + if(curve.ToPtr<IfcBoundedCurve>()) { 1.525 + if(const IfcPolyline* c = curve.ToPtr<IfcPolyline>()) { 1.526 + return new PolyLine(*c,conv); 1.527 + } 1.528 + if(const IfcTrimmedCurve* c = curve.ToPtr<IfcTrimmedCurve>()) { 1.529 + return new TrimmedCurve(*c,conv); 1.530 + } 1.531 + if(const IfcCompositeCurve* c = curve.ToPtr<IfcCompositeCurve>()) { 1.532 + return new CompositeCurve(*c,conv); 1.533 + } 1.534 + //if(const IfcBSplineCurve* c = curve.ToPtr<IfcBSplineCurve>()) { 1.535 + // return new BSplineCurve(*c,conv); 1.536 + //} 1.537 + } 1.538 + 1.539 + if(curve.ToPtr<IfcConic>()) { 1.540 + if(const IfcCircle* c = curve.ToPtr<IfcCircle>()) { 1.541 + return new Circle(*c,conv); 1.542 + } 1.543 + if(const IfcEllipse* c = curve.ToPtr<IfcEllipse>()) { 1.544 + return new Ellipse(*c,conv); 1.545 + } 1.546 + } 1.547 + 1.548 + if(const IfcLine* c = curve.ToPtr<IfcLine>()) { 1.549 + return new Line(*c,conv); 1.550 + } 1.551 + 1.552 + // XXX OffsetCurve2D, OffsetCurve3D not currently supported 1.553 + return NULL; 1.554 +} 1.555 + 1.556 +#ifdef _DEBUG 1.557 +// ------------------------------------------------------------------------------------------------ 1.558 +bool Curve :: InRange(IfcFloat u) const 1.559 +{ 1.560 + const ParamRange range = GetParametricRange(); 1.561 + if (IsClosed()) { 1.562 + return true; 1.563 + //ai_assert(range.first != std::numeric_limits<IfcFloat>::infinity() && range.second != std::numeric_limits<IfcFloat>::infinity()); 1.564 + //u = range.first + fmod(u-range.first,range.second-range.first); 1.565 + } 1.566 + const IfcFloat epsilon = 1e-5; 1.567 + return u - range.first > -epsilon && range.second - u > -epsilon; 1.568 +} 1.569 +#endif 1.570 + 1.571 +// ------------------------------------------------------------------------------------------------ 1.572 +IfcFloat Curve :: GetParametricRangeDelta() const 1.573 +{ 1.574 + const ParamRange& range = GetParametricRange(); 1.575 + return abs(range.second - range.first); 1.576 +} 1.577 + 1.578 +// ------------------------------------------------------------------------------------------------ 1.579 +size_t Curve :: EstimateSampleCount(IfcFloat a, IfcFloat b) const 1.580 +{ 1.581 + ai_assert(InRange(a) && InRange(b)); 1.582 + 1.583 + // arbitrary default value, deriving classes should supply better suited values 1.584 + return 16; 1.585 +} 1.586 + 1.587 +// ------------------------------------------------------------------------------------------------ 1.588 +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) 1.589 +{ 1.590 + ai_assert(samples>1); 1.591 + 1.592 + const IfcFloat delta = (b-a)/samples, inf = std::numeric_limits<IfcFloat>::infinity(); 1.593 + IfcFloat min_point[2] = {a,b}, min_diff[2] = {inf,inf}; 1.594 + IfcFloat runner = a; 1.595 + 1.596 + for (unsigned int i = 0; i < samples; ++i, runner += delta) { 1.597 + const IfcFloat diff = (cv->Eval(runner)-val).SquareLength(); 1.598 + if (diff < min_diff[0]) { 1.599 + min_diff[1] = min_diff[0]; 1.600 + min_point[1] = min_point[0]; 1.601 + 1.602 + min_diff[0] = diff; 1.603 + min_point[0] = runner; 1.604 + } 1.605 + else if (diff < min_diff[1]) { 1.606 + min_diff[1] = diff; 1.607 + min_point[1] = runner; 1.608 + } 1.609 + } 1.610 + 1.611 + ai_assert(min_diff[0] != inf && min_diff[1] != inf); 1.612 + if ( fabs(a-min_point[0]) < threshold || recurse >= max_recurse) { 1.613 + return min_point[0]; 1.614 + } 1.615 + 1.616 + // fix for closed curves to take their wrap-over into account 1.617 + if (cv->IsClosed() && fabs(min_point[0]-min_point[1]) > cv->GetParametricRangeDelta()*0.5 ) { 1.618 + const Curve::ParamRange& range = cv->GetParametricRange(); 1.619 + const IfcFloat wrapdiff = (cv->Eval(range.first)-val).SquareLength(); 1.620 + 1.621 + if (wrapdiff < min_diff[0]) { 1.622 + const IfcFloat t = min_point[0]; 1.623 + min_point[0] = min_point[1] > min_point[0] ? range.first : range.second; 1.624 + min_point[1] = t; 1.625 + } 1.626 + } 1.627 + 1.628 + return RecursiveSearch(cv,val,min_point[0],min_point[1],samples,threshold,recurse+1,max_recurse); 1.629 +} 1.630 + 1.631 +// ------------------------------------------------------------------------------------------------ 1.632 +bool Curve :: ReverseEval(const IfcVector3& val, IfcFloat& paramOut) const 1.633 +{ 1.634 + // note: the following algorithm is not guaranteed to find the 'right' parameter value 1.635 + // in all possible cases, but it will always return at least some value so this function 1.636 + // will never fail in the default implementation. 1.637 + 1.638 + // XXX derive threshold from curve topology 1.639 + const IfcFloat threshold = 1e-4f; 1.640 + const unsigned int samples = 16; 1.641 + 1.642 + const ParamRange& range = GetParametricRange(); 1.643 + paramOut = RecursiveSearch(this,val,range.first,range.second,samples,threshold); 1.644 + 1.645 + return true; 1.646 +} 1.647 + 1.648 +// ------------------------------------------------------------------------------------------------ 1.649 +void Curve :: SampleDiscrete(TempMesh& out,IfcFloat a, IfcFloat b) const 1.650 +{ 1.651 + ai_assert(InRange(a) && InRange(b)); 1.652 + 1.653 + const size_t cnt = std::max(static_cast<size_t>(0),EstimateSampleCount(a,b)); 1.654 + out.verts.reserve( out.verts.size() + cnt ); 1.655 + 1.656 + IfcFloat p = a, delta = (b-a)/cnt; 1.657 + for(size_t i = 0; i < cnt; ++i, p += delta) { 1.658 + out.verts.push_back(Eval(p)); 1.659 + } 1.660 +} 1.661 + 1.662 +// ------------------------------------------------------------------------------------------------ 1.663 +bool BoundedCurve :: IsClosed() const 1.664 +{ 1.665 + return false; 1.666 +} 1.667 + 1.668 +// ------------------------------------------------------------------------------------------------ 1.669 +void BoundedCurve :: SampleDiscrete(TempMesh& out) const 1.670 +{ 1.671 + const ParamRange& range = GetParametricRange(); 1.672 + ai_assert(range.first != std::numeric_limits<IfcFloat>::infinity() && range.second != std::numeric_limits<IfcFloat>::infinity()); 1.673 + 1.674 + return SampleDiscrete(out,range.first,range.second); 1.675 +} 1.676 + 1.677 +} // IFC 1.678 +} // Assimp 1.679 + 1.680 +#endif // ASSIMP_BUILD_NO_IFC_IMPORTER