# 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-9d2fd5bffc1fpull/2/head
parent
5f341dcf00
commit
56a5230d3a
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue