- Further work on IFC, fix transformations, support non-uniform transformations, optimize loading, use recursive algorithm to resolve holes in polygons, implement CSG logic to generate wall openings. The latter is currently disabled.
- Triangulation step now automatically drops polygons with an area of zero. - Add debug preprocessor switch to dump all triangulations to a separate file. - Refactoring, collect some polygon related functions in a separate header, PolyTools.h git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@1002 67173fc5-114c-0410-ac8e-9d2fd5bffc1fpull/1/head
parent
e23767a170
commit
bbd7547fff
File diff suppressed because it is too large
Load Diff
|
@ -654,7 +654,7 @@ namespace {
|
||||||
, SchemaEntry("ifcreldefinesbyproperties",&STEP::ObjectHelper<NotImplemented,0>::Construct )
|
, SchemaEntry("ifcreldefinesbyproperties",&STEP::ObjectHelper<NotImplemented,0>::Construct )
|
||||||
, SchemaEntry("ifccondition",&STEP::ObjectHelper<IfcCondition,0>::Construct )
|
, SchemaEntry("ifccondition",&STEP::ObjectHelper<IfcCondition,0>::Construct )
|
||||||
, SchemaEntry("ifcgridaxis",&STEP::ObjectHelper<NotImplemented,0>::Construct )
|
, SchemaEntry("ifcgridaxis",&STEP::ObjectHelper<NotImplemented,0>::Construct )
|
||||||
, SchemaEntry("ifcrelvoidselement",&STEP::ObjectHelper<NotImplemented,0>::Construct )
|
, SchemaEntry("ifcrelvoidselement",&STEP::ObjectHelper<IfcRelVoidsElement,2>::Construct )
|
||||||
, SchemaEntry("ifcwindow",&STEP::ObjectHelper<IfcWindow,2>::Construct )
|
, SchemaEntry("ifcwindow",&STEP::ObjectHelper<IfcWindow,2>::Construct )
|
||||||
, SchemaEntry("ifcrelflowcontrolelements",&STEP::ObjectHelper<NotImplemented,0>::Construct )
|
, SchemaEntry("ifcrelflowcontrolelements",&STEP::ObjectHelper<NotImplemented,0>::Construct )
|
||||||
, SchemaEntry("ifcrelconnectsporttoelement",&STEP::ObjectHelper<NotImplemented,0>::Construct )
|
, SchemaEntry("ifcrelconnectsporttoelement",&STEP::ObjectHelper<NotImplemented,0>::Construct )
|
||||||
|
@ -1329,7 +1329,16 @@ template <> size_t GenericFill<IfcHalfSpaceSolid>(const DB& db, const LIST& para
|
||||||
template <> size_t GenericFill<IfcPolygonalBoundedHalfSpace>(const DB& db, const LIST& params, IfcPolygonalBoundedHalfSpace* in)
|
template <> size_t GenericFill<IfcPolygonalBoundedHalfSpace>(const DB& db, const LIST& params, IfcPolygonalBoundedHalfSpace* in)
|
||||||
{
|
{
|
||||||
size_t base = GenericFill(db,params,static_cast<IfcHalfSpaceSolid*>(in));
|
size_t base = GenericFill(db,params,static_cast<IfcHalfSpaceSolid*>(in));
|
||||||
// this data structure is not used yet, so there is no code generated to fill its members
|
if (params.GetSize() < 4) { throw STEP::TypeError("expected 4 arguments to IfcPolygonalBoundedHalfSpace"); } do { // convert the 'Position' argument
|
||||||
|
const DataType* arg = params[base++];
|
||||||
|
try { GenericConvert( in->Position, *arg, db ); break; }
|
||||||
|
catch (const TypeError& t) { throw TypeError(t.what() + std::string(" - expected argument 2 to IfcPolygonalBoundedHalfSpace to be a `IfcAxis2Placement3D`")); }
|
||||||
|
} while(0);
|
||||||
|
do { // convert the 'PolygonalBoundary' argument
|
||||||
|
const DataType* arg = params[base++];
|
||||||
|
try { GenericConvert( in->PolygonalBoundary, *arg, db ); break; }
|
||||||
|
catch (const TypeError& t) { throw TypeError(t.what() + std::string(" - expected argument 3 to IfcPolygonalBoundedHalfSpace to be a `IfcBoundedCurve`")); }
|
||||||
|
} while(0);
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
// -----------------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------------
|
||||||
|
@ -1427,22 +1436,19 @@ template <> size_t GenericFill<IfcBooleanResult>(const DB& db, const LIST& param
|
||||||
template <> size_t GenericFill<IfcFeatureElement>(const DB& db, const LIST& params, IfcFeatureElement* in)
|
template <> size_t GenericFill<IfcFeatureElement>(const DB& db, const LIST& params, IfcFeatureElement* in)
|
||||||
{
|
{
|
||||||
size_t base = GenericFill(db,params,static_cast<IfcElement*>(in));
|
size_t base = GenericFill(db,params,static_cast<IfcElement*>(in));
|
||||||
// this data structure is not used yet, so there is no code generated to fill its members
|
if (params.GetSize() < 8) { throw STEP::TypeError("expected 8 arguments to IfcFeatureElement"); } return base;
|
||||||
return base;
|
|
||||||
}
|
}
|
||||||
// -----------------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------------
|
||||||
template <> size_t GenericFill<IfcFeatureElementSubtraction>(const DB& db, const LIST& params, IfcFeatureElementSubtraction* in)
|
template <> size_t GenericFill<IfcFeatureElementSubtraction>(const DB& db, const LIST& params, IfcFeatureElementSubtraction* in)
|
||||||
{
|
{
|
||||||
size_t base = GenericFill(db,params,static_cast<IfcFeatureElement*>(in));
|
size_t base = GenericFill(db,params,static_cast<IfcFeatureElement*>(in));
|
||||||
// this data structure is not used yet, so there is no code generated to fill its members
|
if (params.GetSize() < 8) { throw STEP::TypeError("expected 8 arguments to IfcFeatureElementSubtraction"); } return base;
|
||||||
return base;
|
|
||||||
}
|
}
|
||||||
// -----------------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------------
|
||||||
template <> size_t GenericFill<IfcOpeningElement>(const DB& db, const LIST& params, IfcOpeningElement* in)
|
template <> size_t GenericFill<IfcOpeningElement>(const DB& db, const LIST& params, IfcOpeningElement* in)
|
||||||
{
|
{
|
||||||
size_t base = GenericFill(db,params,static_cast<IfcFeatureElementSubtraction*>(in));
|
size_t base = GenericFill(db,params,static_cast<IfcFeatureElementSubtraction*>(in));
|
||||||
// this data structure is not used yet, so there is no code generated to fill its members
|
if (params.GetSize() < 8) { throw STEP::TypeError("expected 8 arguments to IfcOpeningElement"); } return base;
|
||||||
return base;
|
|
||||||
}
|
}
|
||||||
// -----------------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------------
|
||||||
template <> size_t GenericFill<IfcConditionCriterion>(const DB& db, const LIST& params, IfcConditionCriterion* in)
|
template <> size_t GenericFill<IfcConditionCriterion>(const DB& db, const LIST& params, IfcConditionCriterion* in)
|
||||||
|
@ -2635,6 +2641,22 @@ template <> size_t GenericFill<IfcCondition>(const DB& db, const LIST& params, I
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
// -----------------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------------
|
||||||
|
template <> size_t GenericFill<IfcRelVoidsElement>(const DB& db, const LIST& params, IfcRelVoidsElement* in)
|
||||||
|
{
|
||||||
|
size_t base = GenericFill(db,params,static_cast<IfcRelConnects*>(in));
|
||||||
|
if (params.GetSize() < 6) { throw STEP::TypeError("expected 6 arguments to IfcRelVoidsElement"); } do { // convert the 'RelatingBuildingElement' argument
|
||||||
|
const DataType* arg = params[base++];
|
||||||
|
try { GenericConvert( in->RelatingBuildingElement, *arg, db ); break; }
|
||||||
|
catch (const TypeError& t) { throw TypeError(t.what() + std::string(" - expected argument 4 to IfcRelVoidsElement to be a `IfcElement`")); }
|
||||||
|
} while(0);
|
||||||
|
do { // convert the 'RelatedOpeningElement' argument
|
||||||
|
const DataType* arg = params[base++];
|
||||||
|
try { GenericConvert( in->RelatedOpeningElement, *arg, db ); break; }
|
||||||
|
catch (const TypeError& t) { throw TypeError(t.what() + std::string(" - expected argument 5 to IfcRelVoidsElement to be a `IfcFeatureElementSubtraction`")); }
|
||||||
|
} while(0);
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
// -----------------------------------------------------------------------------------------------------------
|
||||||
template <> size_t GenericFill<IfcWindow>(const DB& db, const LIST& params, IfcWindow* in)
|
template <> size_t GenericFill<IfcWindow>(const DB& db, const LIST& params, IfcWindow* in)
|
||||||
{
|
{
|
||||||
size_t base = GenericFill(db,params,static_cast<IfcBuildingElement*>(in));
|
size_t base = GenericFill(db,params,static_cast<IfcBuildingElement*>(in));
|
||||||
|
@ -2814,7 +2836,18 @@ template <> size_t GenericFill<IfcCartesianTransformationOperator3D>(const DB& d
|
||||||
template <> size_t GenericFill<IfcCartesianTransformationOperator3DnonUniform>(const DB& db, const LIST& params, IfcCartesianTransformationOperator3DnonUniform* in)
|
template <> size_t GenericFill<IfcCartesianTransformationOperator3DnonUniform>(const DB& db, const LIST& params, IfcCartesianTransformationOperator3DnonUniform* in)
|
||||||
{
|
{
|
||||||
size_t base = GenericFill(db,params,static_cast<IfcCartesianTransformationOperator3D*>(in));
|
size_t base = GenericFill(db,params,static_cast<IfcCartesianTransformationOperator3D*>(in));
|
||||||
// this data structure is not used yet, so there is no code generated to fill its members
|
if (params.GetSize() < 7) { throw STEP::TypeError("expected 7 arguments to IfcCartesianTransformationOperator3DnonUniform"); } do { // convert the 'Scale2' argument
|
||||||
|
const DataType* arg = params[base++];
|
||||||
|
if (dynamic_cast<const UNSET*>(&*arg)) break;
|
||||||
|
try { GenericConvert( in->Scale2, *arg, db ); break; }
|
||||||
|
catch (const TypeError& t) { throw TypeError(t.what() + std::string(" - expected argument 5 to IfcCartesianTransformationOperator3DnonUniform to be a `REAL`")); }
|
||||||
|
} while(0);
|
||||||
|
do { // convert the 'Scale3' argument
|
||||||
|
const DataType* arg = params[base++];
|
||||||
|
if (dynamic_cast<const UNSET*>(&*arg)) break;
|
||||||
|
try { GenericConvert( in->Scale3, *arg, db ); break; }
|
||||||
|
catch (const TypeError& t) { throw TypeError(t.what() + std::string(" - expected argument 6 to IfcCartesianTransformationOperator3DnonUniform to be a `REAL`")); }
|
||||||
|
} while(0);
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
// -----------------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -994,7 +994,7 @@ namespace IFC {
|
||||||
typedef NotImplemented IfcRelDefinesByProperties; // (not currently used by Assimp)
|
typedef NotImplemented IfcRelDefinesByProperties; // (not currently used by Assimp)
|
||||||
struct IfcCondition;
|
struct IfcCondition;
|
||||||
typedef NotImplemented IfcGridAxis; // (not currently used by Assimp)
|
typedef NotImplemented IfcGridAxis; // (not currently used by Assimp)
|
||||||
typedef NotImplemented IfcRelVoidsElement; // (not currently used by Assimp)
|
struct IfcRelVoidsElement;
|
||||||
struct IfcWindow;
|
struct IfcWindow;
|
||||||
typedef NotImplemented IfcRelFlowControlElements; // (not currently used by Assimp)
|
typedef NotImplemented IfcRelFlowControlElements; // (not currently used by Assimp)
|
||||||
typedef NotImplemented IfcRelConnectsPortToElement; // (not currently used by Assimp)
|
typedef NotImplemented IfcRelConnectsPortToElement; // (not currently used by Assimp)
|
||||||
|
@ -2376,6 +2376,12 @@ namespace IFC {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// C++ wrapper for IfcRelVoidsElement
|
||||||
|
struct IfcRelVoidsElement : IfcRelConnects, ObjectHelper<IfcRelVoidsElement,2> { IfcRelVoidsElement() : Object("IfcRelVoidsElement") {}
|
||||||
|
Lazy< IfcElement > RelatingBuildingElement;
|
||||||
|
Lazy< IfcFeatureElementSubtraction > RelatedOpeningElement;
|
||||||
|
};
|
||||||
|
|
||||||
// C++ wrapper for IfcWindow
|
// C++ wrapper for IfcWindow
|
||||||
struct IfcWindow : IfcBuildingElement, ObjectHelper<IfcWindow,2> { IfcWindow() : Object("IfcWindow") {}
|
struct IfcWindow : IfcBuildingElement, ObjectHelper<IfcWindow,2> { IfcWindow() : Object("IfcWindow") {}
|
||||||
Maybe< IfcPositiveLengthMeasure::Out > OverallHeight;
|
Maybe< IfcPositiveLengthMeasure::Out > OverallHeight;
|
||||||
|
@ -3980,6 +3986,7 @@ namespace STEP {
|
||||||
DECL_CONV_STUB(IfcWorkControl);
|
DECL_CONV_STUB(IfcWorkControl);
|
||||||
DECL_CONV_STUB(IfcWorkPlan);
|
DECL_CONV_STUB(IfcWorkPlan);
|
||||||
DECL_CONV_STUB(IfcCondition);
|
DECL_CONV_STUB(IfcCondition);
|
||||||
|
DECL_CONV_STUB(IfcRelVoidsElement);
|
||||||
DECL_CONV_STUB(IfcWindow);
|
DECL_CONV_STUB(IfcWindow);
|
||||||
DECL_CONV_STUB(IfcProtectiveDeviceType);
|
DECL_CONV_STUB(IfcProtectiveDeviceType);
|
||||||
DECL_CONV_STUB(IfcJunctionBoxType);
|
DECL_CONV_STUB(IfcJunctionBoxType);
|
||||||
|
|
|
@ -0,0 +1,223 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (ASSIMP)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2010, ASSIMP Development Team
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
with or without modification, are permitted provided that the
|
||||||
|
following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other
|
||||||
|
materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the ASSIMP team, nor the names of its
|
||||||
|
contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior
|
||||||
|
written permission of the ASSIMP Development Team.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file PolyTools.h, various utilities for our dealings with arbitrary polygons */
|
||||||
|
|
||||||
|
#ifndef AI_POLYTOOLS_H_INCLUDED
|
||||||
|
#define AI_POLYTOOLS_H_INCLUDED
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------
|
||||||
|
/** Test if a given point p2 is on the left side of the line formed by p0-p1.
|
||||||
|
* The function accepts an unconstrained template parameter for use with
|
||||||
|
* both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/
|
||||||
|
template <typename T>
|
||||||
|
inline bool OnLeftSideOfLine2D(const T& p0, const T& p1,const T& p2)
|
||||||
|
{
|
||||||
|
return ( (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y) ) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------
|
||||||
|
/** Test if a given point is inside a given triangle in R2.
|
||||||
|
* The function accepts an unconstrained template parameter for use with
|
||||||
|
* both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/
|
||||||
|
template <typename T>
|
||||||
|
inline bool PointInTriangle2D(const T& p0, const T& p1,const T& p2, const T& pp)
|
||||||
|
{
|
||||||
|
// Point in triangle test using baryzentric coordinates
|
||||||
|
const aiVector2D v0 = p1 - p0;
|
||||||
|
const aiVector2D v1 = p2 - p0;
|
||||||
|
const aiVector2D v2 = pp - p0;
|
||||||
|
|
||||||
|
float dot00 = v0 * v0;
|
||||||
|
float dot01 = v0 * v1;
|
||||||
|
float dot02 = v0 * v2;
|
||||||
|
float dot11 = v1 * v1;
|
||||||
|
float dot12 = v1 * v2;
|
||||||
|
|
||||||
|
const float invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
|
||||||
|
dot11 = (dot11 * dot02 - dot01 * dot12) * invDenom;
|
||||||
|
dot00 = (dot00 * dot12 - dot01 * dot02) * invDenom;
|
||||||
|
|
||||||
|
return (dot11 >= 0) && (dot00 >= 0) && (dot11 + dot00 <= 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------
|
||||||
|
/** Compute the signed area of a triangle.
|
||||||
|
* The function accepts an unconstrained template parameter for use with
|
||||||
|
* both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/
|
||||||
|
template <typename T>
|
||||||
|
inline float GetArea2D(const T& v1, const T& v2, const T& v3)
|
||||||
|
{
|
||||||
|
return 0.5f * (v1.x * (v3.y - v2.y) + v2.x * (v1.y - v3.y) + v3.x * (v2.y - v1.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------
|
||||||
|
/** Check whether the winding order of a given polygon is counter-clockwise.
|
||||||
|
* The function accepts an unconstrained template parameter, but is intended
|
||||||
|
* to be used only with aiVector2D and aiVector3D (z axis is ignored, only
|
||||||
|
* x and y are taken into account).
|
||||||
|
* @note Code taken from http://cgm.cs.mcgill.ca/~godfried/teaching/cg-projects/97/Ian/applet1.html and translated to C++
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
inline bool IsCCW(T* in, size_t npoints) {
|
||||||
|
double aa, bb, cc, b, c, theta;
|
||||||
|
double convex_turn;
|
||||||
|
double convex_sum = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < npoints - 2; i++) {
|
||||||
|
aa = ((in[i+2].x - in[i].x) * (in[i+2].x - in[i].x)) +
|
||||||
|
((-in[i+2].y + in[i].y) * (-in[i+2].y + in[i].y));
|
||||||
|
|
||||||
|
bb = ((in[i+1].x - in[i].x) * (in[i+1].x - in[i].x)) +
|
||||||
|
((-in[i+1].y + in[i].y) * (-in[i+1].y + in[i].y));
|
||||||
|
|
||||||
|
cc = ((in[i+2].x - in[i+1].x) *
|
||||||
|
(in[i+2].x - in[i+1].x)) +
|
||||||
|
((-in[i+2].y + in[i+1].y) *
|
||||||
|
(-in[i+2].y + in[i+1].y));
|
||||||
|
|
||||||
|
b = sqrt(bb);
|
||||||
|
c = sqrt(cc);
|
||||||
|
theta = acos((bb + cc - aa) / (2 * b * c));
|
||||||
|
|
||||||
|
if (OnLeftSideOfLine2D(in[i],in[i+2],in[i+1])) {
|
||||||
|
// if (convex(in[i].x, in[i].y,
|
||||||
|
// in[i+1].x, in[i+1].y,
|
||||||
|
// in[i+2].x, in[i+2].y)) {
|
||||||
|
convex_turn = AI_MATH_PI_F - theta;
|
||||||
|
convex_sum += convex_turn;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
convex_sum -= AI_MATH_PI_F - theta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
aa = ((in[1].x - in[npoints-2].x) *
|
||||||
|
(in[1].x - in[npoints-2].x)) +
|
||||||
|
((-in[1].y + in[npoints-2].y) *
|
||||||
|
(-in[1].y + in[npoints-2].y));
|
||||||
|
|
||||||
|
bb = ((in[0].x - in[npoints-2].x) *
|
||||||
|
(in[0].x - in[npoints-2].x)) +
|
||||||
|
((-in[0].y + in[npoints-2].y) *
|
||||||
|
(-in[0].y + in[npoints-2].y));
|
||||||
|
|
||||||
|
cc = ((in[1].x - in[0].x) * (in[1].x - in[0].x)) +
|
||||||
|
((-in[1].y + in[0].y) * (-in[1].y + in[0].y));
|
||||||
|
|
||||||
|
b = sqrt(bb);
|
||||||
|
c = sqrt(cc);
|
||||||
|
theta = acos((bb + cc - aa) / (2 * b * c));
|
||||||
|
|
||||||
|
//if (convex(in[npoints-2].x, in[npoints-2].y,
|
||||||
|
// in[0].x, in[0].y,
|
||||||
|
// in[1].x, in[1].y)) {
|
||||||
|
if (OnLeftSideOfLine2D(in[npoints-2],in[1],in[0])) {
|
||||||
|
convex_turn = AI_MATH_PI_F - theta;
|
||||||
|
convex_sum += convex_turn;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
convex_sum -= AI_MATH_PI_F - theta;
|
||||||
|
}
|
||||||
|
|
||||||
|
return convex_sum >= (2 * AI_MATH_PI_F);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------
|
||||||
|
/** Compute the normal of an arbitrary polygon in R3.
|
||||||
|
*
|
||||||
|
* The code is based on Newell's formula, that is a polygons normal is the ratio
|
||||||
|
* of its area when projected onto the three coordinate axes.
|
||||||
|
*
|
||||||
|
* @param out Receives the output normal
|
||||||
|
* @param num Number of input vertices
|
||||||
|
* @param x X data source. x[ofs_x*n] is the n'th element.
|
||||||
|
* @param y Y data source. y[ofs_y*n] is the y'th element
|
||||||
|
* @param z Z data source. z[ofs_z*n] is the z'th element
|
||||||
|
*
|
||||||
|
* @note The data arrays must have storage for at least num+2 elements. Using
|
||||||
|
* this method is much faster than the 'other' NewellNormal()
|
||||||
|
*/
|
||||||
|
template <int ofs_x, int ofs_y, int ofs_z>
|
||||||
|
inline void NewellNormal (aiVector3D& out, int num, float* x, float* y, float* z)
|
||||||
|
{
|
||||||
|
// Duplicate the first two vertices at the end
|
||||||
|
x[(num+0)*ofs_x] = x[0];
|
||||||
|
x[(num+1)*ofs_x] = x[ofs_x];
|
||||||
|
|
||||||
|
y[(num+0)*ofs_y] = y[0];
|
||||||
|
y[(num+1)*ofs_y] = y[ofs_y];
|
||||||
|
|
||||||
|
z[(num+0)*ofs_z] = z[0];
|
||||||
|
z[(num+1)*ofs_z] = z[ofs_z];
|
||||||
|
|
||||||
|
float sum_xy = 0.0, sum_yz = 0.0, sum_zx = 0.0;
|
||||||
|
|
||||||
|
float *xptr = x +ofs_x, *xlow = x, *xhigh = x + ofs_x*2;
|
||||||
|
float *yptr = y +ofs_y, *ylow = y, *yhigh = y + ofs_y*2;
|
||||||
|
float *zptr = z +ofs_z, *zlow = z, *zhigh = z + ofs_z*2;
|
||||||
|
|
||||||
|
for (int tmp=0; tmp < num; tmp++) {
|
||||||
|
sum_xy += (*xptr) * ( (*yhigh) - (*ylow) );
|
||||||
|
sum_yz += (*yptr) * ( (*zhigh) - (*zlow) );
|
||||||
|
sum_zx += (*zptr) * ( (*xhigh) - (*xlow) );
|
||||||
|
|
||||||
|
xptr += ofs_x;
|
||||||
|
xlow += ofs_x;
|
||||||
|
xhigh += ofs_x;
|
||||||
|
|
||||||
|
yptr += ofs_y;
|
||||||
|
ylow += ofs_y;
|
||||||
|
yhigh += ofs_y;
|
||||||
|
|
||||||
|
zptr += ofs_z;
|
||||||
|
zlow += ofs_z;
|
||||||
|
zhigh += ofs_z;
|
||||||
|
}
|
||||||
|
out = aiVector3D(sum_yz,sum_zx,sum_xy);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // ! Assimp
|
||||||
|
|
||||||
|
#endif
|
|
@ -64,6 +64,16 @@ namespace std {
|
||||||
return ::aiVector3D (max(a.x,b.x),max(a.y,b.y),max(a.z,b.z));
|
return ::aiVector3D (max(a.x,b.x),max(a.y,b.y),max(a.z,b.z));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// std::min for aiVector2D
|
||||||
|
inline ::aiVector2D min (const ::aiVector2D& a, const ::aiVector2D& b) {
|
||||||
|
return ::aiVector2D (min(a.x,b.x),min(a.y,b.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::max for aiVector2D
|
||||||
|
inline ::aiVector2D max (const ::aiVector2D& a, const ::aiVector2D& b) {
|
||||||
|
return ::aiVector2D (max(a.x,b.x),max(a.y,b.y));
|
||||||
|
}
|
||||||
|
|
||||||
// std::min for aiColor4D
|
// std::min for aiColor4D
|
||||||
inline ::aiColor4D min (const ::aiColor4D& a, const ::aiColor4D& b) {
|
inline ::aiColor4D min (const ::aiColor4D& a, const ::aiColor4D& b) {
|
||||||
return ::aiColor4D (min(a.r,b.r),min(a.g,b.g),min(a.b,b.b),min(a.a,b.a));
|
return ::aiColor4D (min(a.r,b.r),min(a.g,b.g),min(a.b,b.b),min(a.a,b.a));
|
||||||
|
@ -126,13 +136,13 @@ struct MinMaxChooser;
|
||||||
|
|
||||||
template <> struct MinMaxChooser<float> {
|
template <> struct MinMaxChooser<float> {
|
||||||
void operator ()(float& min,float& max) {
|
void operator ()(float& min,float& max) {
|
||||||
max = -10e10f;
|
max = -1e10f;
|
||||||
min = 10e10f;
|
min = 1e10f;
|
||||||
}};
|
}};
|
||||||
template <> struct MinMaxChooser<double> {
|
template <> struct MinMaxChooser<double> {
|
||||||
void operator ()(double& min,double& max) {
|
void operator ()(double& min,double& max) {
|
||||||
max = -10e10;
|
max = -1e10;
|
||||||
min = 10e10;
|
min = 1e10;
|
||||||
}};
|
}};
|
||||||
template <> struct MinMaxChooser<unsigned int> {
|
template <> struct MinMaxChooser<unsigned int> {
|
||||||
void operator ()(unsigned int& min,unsigned int& max) {
|
void operator ()(unsigned int& min,unsigned int& max) {
|
||||||
|
@ -142,19 +152,24 @@ template <> struct MinMaxChooser<unsigned int> {
|
||||||
|
|
||||||
template <> struct MinMaxChooser<aiVector3D> {
|
template <> struct MinMaxChooser<aiVector3D> {
|
||||||
void operator ()(aiVector3D& min,aiVector3D& max) {
|
void operator ()(aiVector3D& min,aiVector3D& max) {
|
||||||
max = aiVector3D(-10e10f,-10e10f,-10e10f);
|
max = aiVector3D(-1e10f,-1e10f,-1e10f);
|
||||||
min = aiVector3D( 10e10f, 10e10f, 10e10f);
|
min = aiVector3D( 1e10f, 1e10f, 1e10f);
|
||||||
}};
|
}};
|
||||||
|
template <> struct MinMaxChooser<aiVector2D> {
|
||||||
|
void operator ()(aiVector2D& min,aiVector2D& max) {
|
||||||
|
max = aiVector2D(-1e10f,-1e10f);
|
||||||
|
min = aiVector2D( 1e10f, 1e10f);
|
||||||
|
}};
|
||||||
template <> struct MinMaxChooser<aiColor4D> {
|
template <> struct MinMaxChooser<aiColor4D> {
|
||||||
void operator ()(aiColor4D& min,aiColor4D& max) {
|
void operator ()(aiColor4D& min,aiColor4D& max) {
|
||||||
max = aiColor4D(-10e10f,-10e10f,-10e10f,-10e10f);
|
max = aiColor4D(-1e10f,-1e10f,-1e10f,-1e10f);
|
||||||
min = aiColor4D( 10e10f, 10e10f, 10e10f, 10e10f);
|
min = aiColor4D( 1e10f, 1e10f, 1e10f, 1e10f);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
template <> struct MinMaxChooser<aiQuaternion> {
|
template <> struct MinMaxChooser<aiQuaternion> {
|
||||||
void operator ()(aiQuaternion& min,aiQuaternion& max) {
|
void operator ()(aiQuaternion& min,aiQuaternion& max) {
|
||||||
max = aiQuaternion(-10e10f,-10e10f,-10e10f,-10e10f);
|
max = aiQuaternion(-1e10f,-1e10f,-1e10f,-1e10f);
|
||||||
min = aiQuaternion( 10e10f, 10e10f, 10e10f, 10e10f);
|
min = aiQuaternion( 1e10f, 1e10f, 1e10f, 1e10f);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
template <> struct MinMaxChooser<aiVectorKey> {
|
template <> struct MinMaxChooser<aiVectorKey> {
|
||||||
|
@ -192,59 +207,6 @@ inline void ArrayBounds(const T* in, unsigned int size, T& min, T& max)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
|
||||||
/** @brief Compute the newell normal of a polygon regardless of its shape
|
|
||||||
*
|
|
||||||
* @param out Receives the output normal
|
|
||||||
* @param num Number of input vertices
|
|
||||||
* @param x X data source. x[ofs_x*n] is the n'th element.
|
|
||||||
* @param y Y data source. y[ofs_y*n] is the y'th element
|
|
||||||
* @param z Z data source. z[ofs_z*n] is the z'th element
|
|
||||||
*
|
|
||||||
* @note The data arrays must have storage for at least num+2 elements. Using
|
|
||||||
* this method is much faster than the 'other' NewellNormal()
|
|
||||||
*/
|
|
||||||
template <int ofs_x, int ofs_y, int ofs_z>
|
|
||||||
inline void NewellNormal (aiVector3D& out, int num, float* x, float* y, float* z)
|
|
||||||
{
|
|
||||||
// Duplicate the first two vertices at the end
|
|
||||||
x[(num+0)*ofs_x] = x[0];
|
|
||||||
x[(num+1)*ofs_x] = x[ofs_x];
|
|
||||||
|
|
||||||
y[(num+0)*ofs_y] = y[0];
|
|
||||||
y[(num+1)*ofs_y] = y[ofs_y];
|
|
||||||
|
|
||||||
z[(num+0)*ofs_z] = z[0];
|
|
||||||
z[(num+1)*ofs_z] = z[ofs_z];
|
|
||||||
|
|
||||||
float sum_xy = 0.0, sum_yz = 0.0, sum_zx = 0.0;
|
|
||||||
|
|
||||||
float *xptr = x +ofs_x, *xlow = x, *xhigh = x + ofs_x*2;
|
|
||||||
float *yptr = y +ofs_y, *ylow = y, *yhigh = y + ofs_y*2;
|
|
||||||
float *zptr = z +ofs_z, *zlow = z, *zhigh = z + ofs_z*2;
|
|
||||||
|
|
||||||
for (int tmp=0; tmp < num; tmp++) {
|
|
||||||
sum_xy += (*xptr) * ( (*yhigh) - (*ylow) );
|
|
||||||
sum_yz += (*yptr) * ( (*zhigh) - (*zlow) );
|
|
||||||
sum_zx += (*zptr) * ( (*xhigh) - (*xlow) );
|
|
||||||
|
|
||||||
xptr += ofs_x;
|
|
||||||
xlow += ofs_x;
|
|
||||||
xhigh += ofs_x;
|
|
||||||
|
|
||||||
yptr += ofs_y;
|
|
||||||
ylow += ofs_y;
|
|
||||||
yhigh += ofs_y;
|
|
||||||
|
|
||||||
zptr += ofs_z;
|
|
||||||
zlow += ofs_z;
|
|
||||||
zhigh += ofs_z;
|
|
||||||
}
|
|
||||||
out = aiVector3D(sum_yz,sum_zx,sum_xy);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
/** Little helper function to calculate the quadratic difference
|
/** Little helper function to calculate the quadratic difference
|
||||||
* of two colours.
|
* of two colours.
|
||||||
|
|
|
@ -48,9 +48,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* Self-intersecting or non-planar polygons are not rejected, but
|
* Self-intersecting or non-planar polygons are not rejected, but
|
||||||
* they're probably not triangulated correctly.
|
* they're probably not triangulated correctly.
|
||||||
*
|
*
|
||||||
|
* DEBUG SWITCHES - do not enable any of them in release builds:
|
||||||
|
*
|
||||||
* AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING
|
* AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING
|
||||||
* - generates vertex colors to represent the face winding order.
|
* - generates vertex colors to represent the face winding order.
|
||||||
* the first vertex of a polygon becomes red, the last blue.
|
* the first vertex of a polygon becomes red, the last blue.
|
||||||
|
* AI_BUILD_TRIANGULATE_DEBUG_POLYS
|
||||||
|
* - dump all polygons and their triangulation sequences to
|
||||||
|
* a file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "AssimpPCH.h"
|
#include "AssimpPCH.h"
|
||||||
|
@ -58,8 +63,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifndef ASSIMP_BUILD_NO_TRIANGULATE_PROCESS
|
#ifndef ASSIMP_BUILD_NO_TRIANGULATE_PROCESS
|
||||||
#include "TriangulateProcess.h"
|
#include "TriangulateProcess.h"
|
||||||
#include "ProcessHelper.h"
|
#include "ProcessHelper.h"
|
||||||
|
#include "PolyTools.h"
|
||||||
|
|
||||||
//#define AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING
|
//#define AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING
|
||||||
|
//#define AI_BUILD_TRIANGULATE_DEBUG_POLYS
|
||||||
|
|
||||||
|
#define POLY_GRID_Y 40
|
||||||
|
#define POLY_GRID_X 70
|
||||||
|
#define POLY_GRID_XPAD 20
|
||||||
|
#define POLY_OUTPUT_FILE "assimp_polygons_debug.txt"
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -99,34 +112,6 @@ void TriangulateProcess::Execute( aiScene* pScene)
|
||||||
else DefaultLogger::get()->debug("TriangulateProcess finished. There was nothing to be done.");
|
else DefaultLogger::get()->debug("TriangulateProcess finished. There was nothing to be done.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// Test whether a point p2 is on the left side of the line formed by p0-p1
|
|
||||||
inline bool OnLeftSideOfLine(const aiVector2D& p0, const aiVector2D& p1,const aiVector2D& p2)
|
|
||||||
{
|
|
||||||
return ( (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y) ) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// Test whether a point is inside a given triangle in R2
|
|
||||||
inline bool PointInTriangle2D(const aiVector2D& p0, const aiVector2D& p1,const aiVector2D& p2, const aiVector2D& pp)
|
|
||||||
{
|
|
||||||
// Point in triangle test using baryzentric coordinates
|
|
||||||
const aiVector2D v0 = p1 - p0;
|
|
||||||
const aiVector2D v1 = p2 - p0;
|
|
||||||
const aiVector2D v2 = pp - p0;
|
|
||||||
|
|
||||||
float dot00 = v0 * v0;
|
|
||||||
float dot01 = v0 * v1;
|
|
||||||
float dot02 = v0 * v2;
|
|
||||||
float dot11 = v1 * v1;
|
|
||||||
float dot12 = v1 * v2;
|
|
||||||
|
|
||||||
const float invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
|
|
||||||
dot11 = (dot11 * dot02 - dot01 * dot12) * invDenom;
|
|
||||||
dot00 = (dot00 * dot12 - dot01 * dot02) * invDenom;
|
|
||||||
|
|
||||||
return (dot11 > 0) && (dot00 > 0) && (dot11 + dot00 < 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Triangulates the given mesh.
|
// Triangulates the given mesh.
|
||||||
|
@ -150,17 +135,18 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the output mesh will contain triangles, but no polys anymore
|
|
||||||
pMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
|
|
||||||
pMesh->mPrimitiveTypes &= ~aiPrimitiveType_POLYGON;
|
|
||||||
|
|
||||||
// Find out how many output faces we'll get
|
// Find out how many output faces we'll get
|
||||||
unsigned int numOut = 0, max_out = 0;
|
unsigned int numOut = 0, max_out = 0;
|
||||||
|
bool get_normals = true;
|
||||||
for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
|
for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
|
||||||
aiFace& face = pMesh->mFaces[a];
|
aiFace& face = pMesh->mFaces[a];
|
||||||
if( face.mNumIndices <= 3)
|
if (face.mNumIndices <= 4) {
|
||||||
|
get_normals = false;
|
||||||
|
}
|
||||||
|
if( face.mNumIndices <= 3) {
|
||||||
numOut++;
|
numOut++;
|
||||||
|
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
numOut += face.mNumIndices-2;
|
numOut += face.mNumIndices-2;
|
||||||
max_out = std::max(max_out,face.mNumIndices);
|
max_out = std::max(max_out,face.mNumIndices);
|
||||||
|
@ -171,12 +157,21 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
|
||||||
assert(numOut != pMesh->mNumFaces);
|
assert(numOut != pMesh->mNumFaces);
|
||||||
|
|
||||||
aiVector3D* nor_out = NULL;
|
aiVector3D* nor_out = NULL;
|
||||||
if (!pMesh->mNormals && pMesh->mPrimitiveTypes == aiPrimitiveType_POLYGON) {
|
|
||||||
nor_out = pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
|
// if we don't have normals yet, but expect them to be a cheap side
|
||||||
|
// product of triangulation anyway, allocate storage for them.
|
||||||
|
if (!pMesh->mNormals && get_normals) {
|
||||||
|
// XXX need a mechanism to inform the GenVertexNormals process to treat these normals as preprocessed per-face normals
|
||||||
|
// nor_out = pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
|
||||||
}
|
}
|
||||||
|
|
||||||
aiFace* out = new aiFace[numOut], *curOut = out;
|
// the output mesh will contain triangles, but no polys anymore
|
||||||
std::vector<aiVector3D> temp_verts(max_out+2); /* temporary storage for vertices */
|
pMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
|
||||||
|
pMesh->mPrimitiveTypes &= ~aiPrimitiveType_POLYGON;
|
||||||
|
|
||||||
|
aiFace* out = new aiFace[numOut](), *curOut = out;
|
||||||
|
std::vector<aiVector3D> temp_verts3d(max_out+2); /* temporary storage for vertices */
|
||||||
|
std::vector<aiVector2D> temp_verts(max_out+2);
|
||||||
|
|
||||||
// Apply vertex colors to represent the face winding?
|
// Apply vertex colors to represent the face winding?
|
||||||
#ifdef AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING
|
#ifdef AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING
|
||||||
|
@ -188,6 +183,11 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
|
||||||
aiColor4D* clr = pMesh->mColors[0];
|
aiColor4D* clr = pMesh->mColors[0];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
|
||||||
|
FILE* fout = fopen(POLY_OUTPUT_FILE,"a");
|
||||||
|
#endif
|
||||||
|
|
||||||
// use boost::scoped_array to avoid slow std::vector<bool> specialiations
|
// use boost::scoped_array to avoid slow std::vector<bool> specialiations
|
||||||
boost::scoped_array<bool> done(new bool[max_out]);
|
boost::scoped_array<bool> done(new bool[max_out]);
|
||||||
for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
|
for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
|
||||||
|
@ -205,12 +205,17 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
aiFace* const last_face = curOut;
|
||||||
|
|
||||||
// if it's a simple point,line or triangle: just copy it
|
// if it's a simple point,line or triangle: just copy it
|
||||||
if( face.mNumIndices <= 3)
|
if( face.mNumIndices <= 3)
|
||||||
{
|
{
|
||||||
aiFace& nface = *curOut++;
|
aiFace& nface = *curOut++;
|
||||||
nface.mNumIndices = face.mNumIndices;
|
nface.mNumIndices = face.mNumIndices;
|
||||||
nface.mIndices = face.mIndices;
|
nface.mIndices = face.mIndices;
|
||||||
|
|
||||||
|
face.mIndices = NULL;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
// quadrilaterals can't have ears. trifanning will always work
|
// quadrilaterals can't have ears. trifanning will always work
|
||||||
else if ( face.mNumIndices == 4) {
|
else if ( face.mNumIndices == 4) {
|
||||||
|
@ -225,6 +230,9 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
|
||||||
sface.mIndices[0] = face.mIndices[0];
|
sface.mIndices[0] = face.mIndices[0];
|
||||||
sface.mIndices[1] = face.mIndices[2];
|
sface.mIndices[1] = face.mIndices[2];
|
||||||
sface.mIndices[2] = face.mIndices[3];
|
sface.mIndices[2] = face.mIndices[3];
|
||||||
|
|
||||||
|
face.mIndices = NULL;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -241,12 +249,12 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
|
||||||
// Collect all vertices of of the polygon.
|
// Collect all vertices of of the polygon.
|
||||||
aiVector3D* verts = pMesh->mVertices;
|
aiVector3D* verts = pMesh->mVertices;
|
||||||
for (tmp = 0; tmp < max; ++tmp) {
|
for (tmp = 0; tmp < max; ++tmp) {
|
||||||
temp_verts[tmp] = verts[idx[tmp]];
|
temp_verts3d[tmp] = verts[idx[tmp]];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get newell normal of the polygon. Store it for future use if it's a polygon-only mesh
|
// Get newell normal of the polygon. Store it for future use if it's a polygon-only mesh
|
||||||
aiVector3D n;
|
aiVector3D n;
|
||||||
NewellNormal<3,3,3>(n,max,&temp_verts.front().x,&temp_verts.front().y,&temp_verts.front().z);
|
NewellNormal<3,3,3>(n,max,&temp_verts3d.front().x,&temp_verts3d.front().y,&temp_verts3d.front().z);
|
||||||
if (nor_out) {
|
if (nor_out) {
|
||||||
for (tmp = 0; tmp < max; ++tmp)
|
for (tmp = 0; tmp < max; ++tmp)
|
||||||
nor_out[idx[tmp]] = n;
|
nor_out[idx[tmp]] = n;
|
||||||
|
@ -281,6 +289,35 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
|
||||||
done[tmp] = false;
|
done[tmp] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
|
||||||
|
// plot the plane onto which we mapped the polygon to a 2D ASCII pic
|
||||||
|
aiVector2D bmin,bmax;
|
||||||
|
ArrayBounds(&temp_verts[0],max,bmin,bmax);
|
||||||
|
|
||||||
|
char grid[POLY_GRID_Y][POLY_GRID_X+POLY_GRID_XPAD];
|
||||||
|
std::fill_n((char*)grid,POLY_GRID_Y*(POLY_GRID_X+POLY_GRID_XPAD),' ');
|
||||||
|
|
||||||
|
for (size_t i =0; i < max; ++i) {
|
||||||
|
const aiVector2D& v = (temp_verts[i] - bmin) / (bmax-bmin);
|
||||||
|
const size_t x = static_cast<size_t>(v.x*(POLY_GRID_X-1)), y = static_cast<size_t>(v.y*(POLY_GRID_Y-1));
|
||||||
|
char* loc = grid[y]+x;
|
||||||
|
if (grid[y][x] != ' ') {
|
||||||
|
for(;*loc != ' '; ++loc);
|
||||||
|
*loc++ = '_';
|
||||||
|
}
|
||||||
|
*(loc+sprintf(loc,"%i",i)) = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for(size_t y = 0; y < POLY_GRID_Y; ++y) {
|
||||||
|
grid[y][POLY_GRID_X+POLY_GRID_XPAD-1] = '\0';
|
||||||
|
fprintf(fout,"%s\n",grid[y]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(fout,"\ntriangulation sequence: ");
|
||||||
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
// FIXME: currently this is the slow O(kn) variant with a worst case
|
// FIXME: currently this is the slow O(kn) variant with a worst case
|
||||||
// complexity of O(n^2) (I think). Can be done in O(n).
|
// complexity of O(n^2) (I think). Can be done in O(n).
|
||||||
|
@ -297,12 +334,12 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const aiVector2D* pnt1 = (const aiVector2D*)&temp_verts[ear],
|
const aiVector2D* pnt1 = &temp_verts[ear],
|
||||||
*pnt0 = (const aiVector2D*)&temp_verts[prev],
|
*pnt0 = &temp_verts[prev],
|
||||||
*pnt2 = (const aiVector2D*)&temp_verts[next];
|
*pnt2 = &temp_verts[next];
|
||||||
|
|
||||||
// Must be a convex point. Assuming ccw winding, it must be on the right of the line between p-1 and p+1.
|
// Must be a convex point. Assuming ccw winding, it must be on the right of the line between p-1 and p+1.
|
||||||
if (OnLeftSideOfLine (*pnt0,*pnt2,*pnt1)) {
|
if (OnLeftSideOfLine2D(*pnt0,*pnt2,*pnt1)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,7 +347,7 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
|
||||||
for ( tmp = 0; tmp < max; ++tmp) {
|
for ( tmp = 0; tmp < max; ++tmp) {
|
||||||
|
|
||||||
// We need to compare the actual values because it's possible that multiple indexes in
|
// We need to compare the actual values because it's possible that multiple indexes in
|
||||||
// the polygon are refering to the same position. concave_polygon.obj is a sample
|
// the polygon are referring to the same position. concave_polygon.obj is a sample
|
||||||
//
|
//
|
||||||
// FIXME: Use 'epsiloned' comparisons instead? Due to numeric inaccuracies in
|
// FIXME: Use 'epsiloned' comparisons instead? Due to numeric inaccuracies in
|
||||||
// PointInTriangle() I'm guessing that it's actually possible to construct
|
// PointInTriangle() I'm guessing that it's actually possible to construct
|
||||||
|
@ -324,12 +361,12 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
|
||||||
if (tmp != max) {
|
if (tmp != max) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this vertex is an ear
|
// this vertex is an ear
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (num_found == 2) {
|
if (num_found == 2) {
|
||||||
|
|
||||||
// Due to the 'two ear theorem', every simple polygon with more than three points must
|
// Due to the 'two ear theorem', every simple polygon with more than three points must
|
||||||
// have 2 'ears'. Here's definitely someting wrong ... but we don't give up yet.
|
// have 2 'ears'. Here's definitely someting wrong ... but we don't give up yet.
|
||||||
//
|
//
|
||||||
|
@ -337,6 +374,13 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
|
||||||
// Instead we're continuting with the standard trifanning algorithm which we'd
|
// Instead we're continuting with the standard trifanning algorithm which we'd
|
||||||
// use if we had only convex polygons. That's life.
|
// use if we had only convex polygons. That's life.
|
||||||
DefaultLogger::get()->error("Failed to triangulate polygon (no ear found). Probably not a simple polygon?");
|
DefaultLogger::get()->error("Failed to triangulate polygon (no ear found). Probably not a simple polygon?");
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
|
||||||
|
fprintf(fout,"critical error here, no ear found! ");
|
||||||
|
#endif
|
||||||
|
num = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
curOut -= (max-num); /* undo all previous work */
|
curOut -= (max-num); /* undo all previous work */
|
||||||
for (tmp = 0; tmp < max-2; ++tmp) {
|
for (tmp = 0; tmp < max-2; ++tmp) {
|
||||||
|
@ -346,9 +390,10 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
|
||||||
if (!nface.mIndices)
|
if (!nface.mIndices)
|
||||||
nface.mIndices = new unsigned int[3];
|
nface.mIndices = new unsigned int[3];
|
||||||
|
|
||||||
nface.mIndices[0] = idx[0];
|
nface.mIndices[0] = 0;
|
||||||
nface.mIndices[1] = idx[tmp+1];
|
nface.mIndices[1] = tmp+1;
|
||||||
nface.mIndices[2] = idx[tmp+2];
|
nface.mIndices[2] = tmp+2;
|
||||||
|
|
||||||
}
|
}
|
||||||
num = 0;
|
num = 0;
|
||||||
break;
|
break;
|
||||||
|
@ -362,9 +407,9 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup indices for the new triangle ...
|
// setup indices for the new triangle ...
|
||||||
nface.mIndices[0] = idx[prev];
|
nface.mIndices[0] = prev;
|
||||||
nface.mIndices[1] = idx[ear];
|
nface.mIndices[1] = ear;
|
||||||
nface.mIndices[2] = idx[next];
|
nface.mIndices[2] = next;
|
||||||
|
|
||||||
// exclude the ear from most further processing
|
// exclude the ear from most further processing
|
||||||
done[ear] = true;
|
done[ear] = true;
|
||||||
|
@ -374,21 +419,67 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
|
||||||
// We have three indices forming the last 'ear' remaining. Collect them.
|
// We have three indices forming the last 'ear' remaining. Collect them.
|
||||||
aiFace& nface = *curOut++;
|
aiFace& nface = *curOut++;
|
||||||
nface.mNumIndices = 3;
|
nface.mNumIndices = 3;
|
||||||
nface.mIndices = face.mIndices;
|
if (!nface.mIndices) {
|
||||||
|
nface.mIndices = new unsigned int[3];
|
||||||
|
}
|
||||||
|
|
||||||
for (tmp = 0; done[tmp]; ++tmp);
|
for (tmp = 0; done[tmp]; ++tmp);
|
||||||
idx[0] = idx[tmp];
|
nface.mIndices[0] = tmp;
|
||||||
|
|
||||||
for (++tmp; done[tmp]; ++tmp);
|
for (++tmp; done[tmp]; ++tmp);
|
||||||
idx[1] = idx[tmp];
|
nface.mIndices[1] = tmp;
|
||||||
|
|
||||||
for (++tmp; done[tmp]; ++tmp);
|
for (++tmp; done[tmp]; ++tmp);
|
||||||
idx[2] = idx[tmp];
|
nface.mIndices[2] = tmp;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
face.mIndices = NULL; /* prevent unintended deletion of our awesome results. would be a pity */
|
|
||||||
|
#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
|
||||||
|
|
||||||
|
for(aiFace* f = last_face; f != curOut; ++f) {
|
||||||
|
unsigned int* i = f->mIndices;
|
||||||
|
fprintf(fout," (%i %i %i)",i[0],i[1],i[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(fout,"\n*********************************************************************\n");
|
||||||
|
fflush(fout);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for(aiFace* f = last_face; f != curOut; ) {
|
||||||
|
unsigned int* i = f->mIndices;
|
||||||
|
|
||||||
|
// drop dumb 0-area triangles
|
||||||
|
if (fabs(GetArea2D(temp_verts[i[0]],temp_verts[i[1]],temp_verts[i[2]])) < 1e-5f) {
|
||||||
|
DefaultLogger::get()->debug("Dropping triangle with area 0");
|
||||||
|
--curOut;
|
||||||
|
|
||||||
|
delete[] f->mIndices;
|
||||||
|
f->mIndices = NULL;
|
||||||
|
|
||||||
|
for(aiFace* ff = f; ff != curOut; ++ff) {
|
||||||
|
ff->mNumIndices = (ff+1)->mNumIndices;
|
||||||
|
ff->mIndices = (ff+1)->mIndices;
|
||||||
|
(ff+1)->mIndices = NULL;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
i[0] = idx[i[0]];
|
||||||
|
i[1] = idx[i[1]];
|
||||||
|
i[2] = idx[i[2]];
|
||||||
|
++f;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] face.mIndices;
|
||||||
|
face.mIndices = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
|
||||||
|
fclose(fout);
|
||||||
|
#endif
|
||||||
|
|
||||||
// kill the old faces
|
// kill the old faces
|
||||||
delete [] pMesh->mFaces;
|
delete [] pMesh->mFaces;
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,12 @@
|
||||||
# code generator. Also, the names of all used entities need to be present
|
# code generator. Also, the names of all used entities need to be present
|
||||||
# in the source code for this to work.
|
# in the source code for this to work.
|
||||||
|
|
||||||
|
IfcCartesianTransformationOperator3DnonUniform
|
||||||
|
IfcFeatureElementSubtraction
|
||||||
|
IfcRelVoidsElement
|
||||||
|
IfcOpeningElement
|
||||||
|
# IfcRelFillsElement
|
||||||
|
IfcPolygonalBoundedHalfSpace
|
||||||
IfcPlane
|
IfcPlane
|
||||||
IfcHalfSpaceSolid
|
IfcHalfSpaceSolid
|
||||||
IfcAxis1Placement
|
IfcAxis1Placement
|
||||||
|
|
|
@ -2518,6 +2518,10 @@
|
||||||
RelativePath="..\..\code\ParsingUtils.h"
|
RelativePath="..\..\code\ParsingUtils.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\code\PolyTools.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\code\Profiler.h"
|
RelativePath="..\..\code\Profiler.h"
|
||||||
>
|
>
|
||||||
|
|
Loading…
Reference in New Issue