- IFC: IfcTrimmingCurve sampling code now supports trimming by points rather than by parameter values.

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@1052 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
pull/2/head
aramis_acg 2011-07-18 01:13:40 +00:00
parent 56a5230d3a
commit 409eb6cee7
3 changed files with 115 additions and 18 deletions

View File

@ -84,7 +84,10 @@ public:
// --------------------------------------------------
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) );
a = fmod(a,360.f);
b = fmod(b,360.f);
return static_cast<size_t>( fabs(ceil(( b-a)) / conv.settings.conicSamplingAngle) );
}
// --------------------------------------------------
@ -340,6 +343,7 @@ public:
TrimmedCurve(const IfcTrimmedCurve& entity, ConversionData& conv)
: BoundedCurve(entity,conv)
, entity(entity)
, ok()
{
base = boost::shared_ptr<const Curve>(Curve::Convert(entity.BasisCurve,conv));
@ -350,34 +354,39 @@ public:
// two representations they prefer, even though an information invariant
// claims that they must be identical if both are present.
// oh well.
bool ok = false;
bool have_param = false, have_point = false;
aiVector3D point;
BOOST_FOREACH(const Entry sel,entity.Trim1) {
if (const EXPRESS::REAL* const r = sel->ToPtr<EXPRESS::REAL>()) {
range.first = *r;
ok = true;
have_param = true;
break;
}
}
if (!ok) {
IFCImporter::LogError("trimming by curve points not currently supported, skipping first cut point");
range.first = base->GetParametricRange().first;
if (range.first == std::numeric_limits<float>::infinity()) {
range.first = 0;
else if (const IfcCartesianPoint* const r = sel->ResolveSelectPtr<IfcCartesianPoint>(conv.db)) {
ConvertCartesianPoint(point,*r);
have_point = true;
}
}
ok = false;
if (!have_param) {
if (!have_point || !base->ReverseEval(point,range.first)) {
throw CurveError("IfcTrimmedCurve: failed to read first trim parameter, ignoring curve");
}
}
have_param = false, have_point = false;
BOOST_FOREACH(const Entry sel,entity.Trim2) {
if (const EXPRESS::REAL* const r = sel->ToPtr<EXPRESS::REAL>()) {
range.second = *r;
ok = true;
have_param = true;
break;
}
else if (const IfcCartesianPoint* const r = sel->ResolveSelectPtr<IfcCartesianPoint>(conv.db)) {
ConvertCartesianPoint(point,*r);
have_point = true;
}
if (!ok) {
IFCImporter::LogError("trimming by curve points not currently supported, skipping second cut point");
range.second = base->GetParametricRange().second;
if (range.second == std::numeric_limits<float>::infinity()) {
range.second = 0;
}
if (!have_param) {
if (!have_point || !base->ReverseEval(point,range.second)) {
throw CurveError("IfcTrimmedCurve: failed to read second trim parameter, ignoring curve");
}
}
@ -430,6 +439,7 @@ private:
ParamRange range;
float maxval;
bool agree_sense;
bool ok;
boost::shared_ptr<const Curve> base;
};
@ -556,6 +566,67 @@ size_t Curve :: EstimateSampleCount(float a, float b) const
return 16;
}
// ------------------------------------------------------------------------------------------------
float RecursiveSearch(const Curve* cv, const aiVector3D& val, float a, float b, unsigned int samples, float treshold, unsigned int recurse = 0, unsigned int max_recurse = 15)
{
ai_assert(samples>1);
const float delta = (b-a)/samples, inf = std::numeric_limits<float>::infinity();
float min_point[2] = {a,b}, min_diff[2] = {inf,inf};
float runner = a;
for (unsigned int i = 0; i < samples; ++i, runner += delta) {
const float diff = (cv->Eval(runner)-val).SquareLength();
if (diff < min_diff[0]) {
min_diff[1] = min_diff[0];
min_point[1] = min_point[0];
min_diff[0] = diff;
min_point[0] = runner;
}
else if (diff < min_diff[1]) {
min_diff[1] = diff;
min_point[1] = runner;
}
}
ai_assert(min_diff[0] != inf && min_diff[1] != inf);
if ( fabs(a-min_point[0]) < treshold || recurse >= max_recurse) {
return min_point[0];
}
// fix for closed curves to take their wrap-over into account
if (cv->IsClosed() && fabs(min_point[0]-min_point[1]) > cv->GetParametricRangeDelta()*0.5 ) {
const Curve::ParamRange& range = cv->GetParametricRange();
const float wrapdiff = (cv->Eval(range.first)-val).SquareLength();
if (wrapdiff < min_diff[0]) {
const float t = min_point[0];
min_point[0] = min_point[1] > min_point[0] ? range.first : range.second;
min_point[1] = t;
}
}
return RecursiveSearch(cv,val,min_point[0],min_point[1],samples,treshold,recurse+1,max_recurse);
}
// ------------------------------------------------------------------------------------------------
bool Curve :: ReverseEval(const aiVector3D& val, float& paramOut) const
{
// note: the following algorithm is not guaranteed to find the 'right' parameter value
// in all possible cases, but it will always return at least some value so this function
// will never fail in the default implementation.
// XXX derive treshold from curve topology
const float treshold = 1e-4;
const unsigned int samples = 16;
const ParamRange& range = GetParametricRange();
paramOut = RecursiveSearch(this,val,range.first,range.second,samples,treshold);
return true;
}
// ------------------------------------------------------------------------------------------------
void Curve :: SampleDiscrete(TempMesh& out,float a, float b) const
{

View File

@ -73,7 +73,13 @@ bool ProcessCurve(const IfcCurve& curve, TempMesh& meshout, ConversionData& con
// we must have a bounded curve at this point
if (const BoundedCurve* bc = dynamic_cast<const BoundedCurve*>(cv.get())) {
try {
bc->SampleDiscrete(meshout);
}
catch(const CurveError& cv) {
IFCImporter::LogError(cv.s+ " (error occurred while processing curve)");
return false;
}
meshout.vertcnt.push_back(meshout.verts.size());
return true;
}

View File

@ -194,6 +194,21 @@ void AssignAddedMeshes(std::vector<unsigned int>& mesh_indices,aiNode* nd,Conver
// IFCCurve.cpp
// ------------------------------------------------------------------------------------------------
// Custom exception for use by members of the Curve class
// ------------------------------------------------------------------------------------------------
class CurveError
{
public:
CurveError(const std::string& s)
: s(s)
{
}
std::string s;
};
// ------------------------------------------------------------------------------------------------
// Temporary representation for an arbitrary sub-class of IfcCurve. Used to sample the curves
// to obtain a list of line segments.
@ -219,6 +234,11 @@ public:
// evaluate the curve at the given parametric position
virtual aiVector3D Eval(float p) const = 0;
// try to match a point on the curve to a given parameter
// for self-intersecting curves, the result is not ambiguous and
// it is undefined which parameter is returned.
virtual bool ReverseEval(const aiVector3D& val, float& paramOut) const;
// get the range of the curve (both inclusive).
// +inf and -inf are valid return values, the curve is not bounded in such a case.
virtual std::pair<float,float> GetParametricRange() const = 0;