# IFC: improve IfcTrimmedCurve implementation and support wrap-over parameters for closed, conic curves.

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@1051 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
pull/2/head
aramis_acg 2011-07-17 23:35:39 +00:00
parent 5f341dcf00
commit 56a5230d3a
2 changed files with 171 additions and 75 deletions

View File

@ -77,7 +77,18 @@ public:
public: public:
// -------------------------------------------------- // --------------------------------------------------
std::pair<float,float> GetParametricRange() const { bool IsClosed() const {
return true;
}
// --------------------------------------------------
size_t EstimateSampleCount(float a, float b) const {
ai_assert(InRange(a) && InRange(b));
return static_cast<size_t>( ceil((b-a) / conv.settings.conicSamplingAngle) );
}
// --------------------------------------------------
ParamRange GetParametricRange() const {
return std::make_pair(0.f,360.f); return std::make_pair(0.f,360.f);
} }
@ -161,13 +172,40 @@ public:
public: public:
// --------------------------------------------------
bool IsClosed() const {
return false;
}
// -------------------------------------------------- // --------------------------------------------------
aiVector3D Eval(float u) const { aiVector3D Eval(float u) const {
return p + u*v; return p + u*v;
} }
// -------------------------------------------------- // --------------------------------------------------
std::pair<float,float> GetParametricRange() const { size_t EstimateSampleCount(float a, float b) const {
ai_assert(InRange(a) && InRange(b));
// two points are always sufficient for a line segment
return a==b ? 1 : 2;
}
// --------------------------------------------------
void SampleDiscrete(TempMesh& out,float a, float b) const
{
ai_assert(InRange(a) && InRange(b));
if (a == b) {
out.verts.push_back(Eval(a));
return;
}
out.verts.reserve(out.verts.size()+2);
out.verts.push_back(Eval(a));
out.verts.push_back(Eval(b));
}
// --------------------------------------------------
ParamRange GetParametricRange() const {
const float inf = std::numeric_limits<float>::infinity(); const float inf = std::numeric_limits<float>::infinity();
return std::make_pair(-inf,+inf); return std::make_pair(-inf,+inf);
@ -218,7 +256,7 @@ public:
total = 0.f; total = 0.f;
BOOST_FOREACH(boost::shared_ptr< const BoundedCurve > curve, curves) { BOOST_FOREACH(boost::shared_ptr< const BoundedCurve > curve, curves) {
const std::pair<float,float> range = curve->GetParametricRange(); const ParamRange range = curve->GetParametricRange();
total += range.second-range.first; total += range.second-range.first;
} }
} }
@ -233,7 +271,7 @@ public:
float acc = 0; float acc = 0;
BOOST_FOREACH(boost::shared_ptr< const BoundedCurve > curve, curves) { BOOST_FOREACH(boost::shared_ptr< const BoundedCurve > curve, curves) {
const std::pair<float,float> range = curve->GetParametricRange(); const ParamRange& range = curve->GetParametricRange();
const float delta = range.second-range.first; const float delta = range.second-range.first;
if (u < acc+delta) { if (u < acc+delta) {
return curve->Eval( (u-acc) + range.first ); return curve->Eval( (u-acc) + range.first );
@ -246,22 +284,39 @@ public:
} }
// -------------------------------------------------- // --------------------------------------------------
float SuggestNext(float u) const { size_t EstimateSampleCount(float a, float b) const {
ai_assert(InRange(a) && InRange(b));
size_t cnt = 0;
float acc = 0; float acc = 0;
BOOST_FOREACH(boost::shared_ptr< const BoundedCurve > curve, curves) { BOOST_FOREACH(boost::shared_ptr< const BoundedCurve > curve, curves) {
const std::pair<float,float> range = curve->GetParametricRange(); const ParamRange& range = curve->GetParametricRange();
const float delta = range.second-range.first; const float delta = range.second-range.first;
if (u < acc+delta) { if (a <= acc+delta && b >= acc) {
return curve->SuggestNext( (u-acc) + range.first ) - range.first + acc; cnt += curve->EstimateSampleCount( std::max(0.f,a-acc) + range.first, std::min(delta,b-acc) + range.first );
} }
acc += delta; acc += delta;
} }
return std::numeric_limits<float>::infinity();
return cnt;
} }
// -------------------------------------------------- // --------------------------------------------------
std::pair<float,float> GetParametricRange() const { void SampleDiscrete(TempMesh& out,float a, float b) const
{
ai_assert(InRange(a) && InRange(b));
const size_t cnt = EstimateSampleCount(a,b);
out.verts.reserve(out.verts.size() + cnt);
BOOST_FOREACH(boost::shared_ptr< const BoundedCurve > curve, curves) {
curve->SampleDiscrete(out);
}
}
// --------------------------------------------------
ParamRange GetParametricRange() const {
return std::make_pair(0.f,total); return std::make_pair(0.f,total);
} }
@ -326,48 +381,55 @@ public:
} }
} }
agree_sense = IsTrue(entity.SenseAgreement);
if( !agree_sense ) {
std::swap(range.first,range.second);
}
// "NOTE In case of a closed curve, it may be necessary to increment t1 or t2
// by the parametric length for consistency with the sense flag."
if (base->IsClosed()) {
if( range.first > range.second ) {
range.second += base->GetParametricRangeDelta();
}
}
maxval = range.second-range.first; maxval = range.second-range.first;
ai_assert(maxval >= 0);
} }
public: public:
// -------------------------------------------------- // --------------------------------------------------
aiVector3D Eval(float p) const { aiVector3D Eval(float p) const {
p = std::min(range.second, std::max(range.first+p,range.first)); ai_assert(InRange(p));
if (!IsTrue(entity.SenseAgreement)) { return base->Eval( TrimParam(p) );
p = range.second - (p-range.first);
}
return base->Eval( p );
} }
// -------------------------------------------------- // --------------------------------------------------
float SuggestNext(float u) const { size_t EstimateSampleCount(float a, float b) const {
if (u >= maxval) { ai_assert(InRange(a) && InRange(b));
return std::numeric_limits<float>::infinity(); return base->EstimateSampleCount(TrimParam(a),TrimParam(b));
}
if (const Line* const l = dynamic_cast<const Line*>(base.get())) {
// a line is, well, a line .. so two points are always sufficient to represent it
return maxval;
}
if (const Conic* const l = dynamic_cast<const Conic*>(base.get())) {
// the suitable sampling density for conics is a configuration property
return std::min(maxval, static_cast<float>( u + maxval/ceil(maxval/conv.settings.conicSamplingAngle)) );
}
return BoundedCurve::SuggestNext(u);
} }
// -------------------------------------------------- // --------------------------------------------------
std::pair<float,float> GetParametricRange() const { ParamRange GetParametricRange() const {
return std::make_pair(0,maxval); return std::make_pair(0,maxval);
} }
private:
// --------------------------------------------------
float TrimParam(float f) const {
return agree_sense ? f + range.first : range.second - f;
}
private: private:
const IfcTrimmedCurve& entity; const IfcTrimmedCurve& entity;
std::pair<float,float> range; ParamRange range;
float maxval; float maxval;
bool agree_sense;
boost::shared_ptr<const Curve> base; boost::shared_ptr<const Curve> base;
}; };
@ -399,11 +461,10 @@ public:
// -------------------------------------------------- // --------------------------------------------------
aiVector3D Eval(float p) const { aiVector3D Eval(float p) const {
if (p < 0.f) { ai_assert(InRange(p));
return points.front();
}
const size_t b = static_cast<size_t>(floor(p)); const size_t b = static_cast<size_t>(floor(p));
if (b >= points.size()-1) { if (b == points.size()-1) {
return points.back(); return points.back();
} }
@ -412,15 +473,13 @@ public:
} }
// -------------------------------------------------- // --------------------------------------------------
float SuggestNext(float u) const { size_t EstimateSampleCount(float a, float b) const {
if (u > points.size()-1) { ai_assert(InRange(a) && InRange(b));
return std::numeric_limits<float>::infinity(); return static_cast<size_t>( ceil(b) - floor(a) );
}
return ::floor(u)+1;
} }
// -------------------------------------------------- // --------------------------------------------------
std::pair<float,float> GetParametricRange() const { ParamRange GetParametricRange() const {
return std::make_pair(0.f,static_cast<float>(points.size()-1)); return std::make_pair(0.f,static_cast<float>(points.size()-1));
} }
@ -468,40 +527,62 @@ Curve* Curve :: Convert(const IFC::IfcCurve& curve,ConversionData& conv)
return NULL; return NULL;
} }
#ifdef _DEBUG
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
float BoundedCurve :: SuggestNext(float u) const bool Curve :: InRange(float u) const
{ {
// the default behavior is to subdivide each curve into approximately 32 linear segments const ParamRange range = GetParametricRange();
const unsigned int segments = 32; if (IsClosed()) {
ai_assert(range.first != std::numeric_limits<float>::infinity() && range.second != std::numeric_limits<float>::infinity());
const std::pair<float,float> range = GetParametricRange(); u = range.first + fmod(u-range.first,range.second-range.first);
const float delta = range.second - range.first, perseg = delta/segments;
if (u < range.first) {
return range.first;
} }
return u >= range.first && u <= range.second;
}
#endif
u = u+perseg; // ------------------------------------------------------------------------------------------------
if (u > range.second) { float Curve :: GetParametricRangeDelta() const
return std::numeric_limits<float>::infinity(); {
const ParamRange& range = GetParametricRange();
return range.second - range.first;
}
// ------------------------------------------------------------------------------------------------
size_t Curve :: EstimateSampleCount(float a, float b) const
{
ai_assert(InRange(a) && InRange(b));
// arbitrary default value, deriving classes should supply better suited values
return 16;
}
// ------------------------------------------------------------------------------------------------
void Curve :: SampleDiscrete(TempMesh& out,float a, float b) const
{
ai_assert(InRange(a) && InRange(b));
const size_t cnt = std::max(static_cast<size_t>(0),EstimateSampleCount(a,b));
out.verts.reserve( out.verts.size() + cnt );
float p = a, delta = (b-a)/cnt;
for(size_t i = 0; i < cnt; ++i, p += delta) {
out.verts.push_back(Eval(p));
} }
}
return u; // ------------------------------------------------------------------------------------------------
bool BoundedCurve :: IsClosed() const
{
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void BoundedCurve :: SampleDiscrete(TempMesh& out) const void BoundedCurve :: SampleDiscrete(TempMesh& out) const
{ {
const std::pair<float,float> range = GetParametricRange(); const ParamRange& range = GetParametricRange();
const float inf = std::numeric_limits<float>::infinity(); ai_assert(range.first != std::numeric_limits<float>::infinity() && range.second != std::numeric_limits<float>::infinity());
size_t cnt = 0; return SampleDiscrete(out,range.first,range.second);
float u = range.first;
do ++cnt; while( (u = SuggestNext(u)) != inf );
out.verts.reserve(cnt);
u = range.first;
do out.verts.push_back(Eval(u)); while( (u = SuggestNext(u)) != inf );
} }
} // IFC } // IFC

View File

@ -209,12 +209,32 @@ protected:
public: public:
typedef std::pair<float,float> ParamRange;
public:
// check if a curve is closed
virtual bool IsClosed() const = 0;
// evaluate the curve at the given parametric position // evaluate the curve at the given parametric position
virtual aiVector3D Eval(float p) const = 0; virtual aiVector3D Eval(float p) const = 0;
// get the range of the curve (both inclusive). // get the range of the curve (both inclusive).
// +inf and -inf are valid return values, the curve is not bounded in such a case. // +inf and -inf are valid return values, the curve is not bounded in such a case.
virtual std::pair<float,float> GetParametricRange() const = 0; virtual std::pair<float,float> GetParametricRange() const = 0;
float GetParametricRangeDelta() const;
// estimate the number of sample points that this curve will require
virtual size_t EstimateSampleCount(float start,float end) const;
// intelligently sample the curve based on the current settings
// and append the result to the mesh
virtual void SampleDiscrete(TempMesh& out,float start,float end) const;
#ifdef _DEBUG
// check if a particular parameter value lies within the well-defined range
bool InRange(float) const;
#endif
public: public:
@ -241,18 +261,13 @@ public:
public: public:
// given a point on the curve, suggest a suitable next point for bool IsClosed() const;
// discrete sampling. The returned parameter value should be
// based on two considerations:
// a) curve geometry is to be preserved
// b) detail level should be chosen based on importer settings
// and (possibly) importance and dimension of the spatial
// structure.
// return +inf if the suggestion is to stop sampling.
virtual float SuggestNext(float u) const;
// intelligently sample the curve based on Eval() and SuggestNext() public:
// sample the entire curve
void SampleDiscrete(TempMesh& out) const; void SampleDiscrete(TempMesh& out) const;
using Curve::SampleDiscrete;
}; };