///////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
// All rights reserved.
//
// This software and its documentation and related materials are owned by
// the Alliance. The software may only be incorporated into application
// programs owned by members of the Alliance, subject to a signed
// Membership Agreement and Supplemental Software License Agreement with the
// Alliance. The structure and organization of this software are the valuable
// trade secrets of the Alliance and its suppliers. The software is also
// protected by copyright law and international treaty provisions. Application
// programs incorporating this software must include the following statement
// with their copyright notices:
//
// This application incorporates Open Design Alliance software pursuant to a license
// agreement with Open Design Alliance.
// Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
// All rights reserved.
//
// By use of this software, its documentation or related materials, you
// acknowledge and accept the above terms.
///////////////////////////////////////////////////////////////////////////////
#ifndef __FMMDL_BODY_H__
#define __FMMDL_BODY_H__
#include "Modeler/FMMdlBase.h"
#include "FMContour3D.h"
#include "FMProfile3D.h"
class OdGeCircArc3d;
namespace GeMesh { class OdGeTrMesh; }
namespace FacetModeler
{
/** \details
Represents facet body objects.
*/
class FMGEOMETRY_API Body
{
public:
/** \details
Default constructor.
*/
Body();
/** \details
Assignment constructor.
\param B [in] Body to assign.
\remarks
Doesn't create a copy of the body, only copies references.
*/
Body(const Body& B);
/** \details
Assignment operator.
\param B [in] Body to assign.
\returns Reference to this body.
\remarks
Doesn't create a copy of the body, only copies the implementation (BodyImpl) pointer.
*/
Body& operator = (const Body& B);
/** \details
Checks if the body is equal to the specified body.
\param aBody [in] Body to compare with.
\returns false if at least one vertex does not match with the other body, or true otherwise.
*/
bool operator == (const Body& aBody) const;
/** \details
Checks if the body is not equal to the specified body.
\param aBody [in] Body to compare with.
\returns true if at least one vertex does not match with the other body, or false otherwise.
*/
bool operator != (const Body& aBody) const;
/** \details
Clears the body.
*/
void clear();
/** \details
Creates a copy of the body.
\returns Copy of the Body object.
*/
Body clone() const;
/** \details
Combines this body and operand into a single body.
\param rAnother [in] Second body to combine with.
\returns Resulting combined body.
\remarks
Clears this body and operand.
*/
Body combine(Body& rAnother);
/** \details
Decomposes the body into one or more lump bodies.
\param aLumps [out] Array of lump bodies.
\remarks
A “lump” is a body with a single continuous 3D volume.
A lump has one outer shell and, possibly, several inner shells that represent cavities.
Clears this body.
*/
void decomposeIntoLumps(std::vector
& aLumps);
/** \details
Transforms the body by the specified matrix.
\param mMatrix [in] Transformation matrix as OdGeMatrix3d.
*/
void transform(const OdGeMatrix3d& mMatrix);
/** \details
Inverts the body.
*/
void negate();
/** \details
Regenerates pair edges.
*/
void regeneratePairEdges();
/** \details
Deletes unused vertices from the body.
*/
void deleteUnusedVertices();
/** \details
Deletes invalid faces from the body.
*/
void deleteInvalidFaces();
/** \details
Merges coincident vertices.
\returns true if at least two coincident vertices are merged.
*/
bool mergeCoincidentVertices();
/** \details
Merges coplanar faces and collinear edges.
\param mergeOnlyWithDiffrentFlags [in] If true two faces will be merged
only if they have equals flags.
*/
void mergeCoplanarEntities(bool mergeOnlyWithDiffrentFlags = false);
/** \details
Checks whether the body has non-manifold edges.
\returns true if at least one non-manifold edge is found, or false otherwise.
*/
bool containsNonManifoldEdges() const;
/** \details
Checks the body for validity.
\param pFirstErrorDetected [out] (Optional) Error result string.
\returns true if the body is valid, or false otherwise.
\remarks
If an error is detected and pFirstErrorDetected is provided, the method
returns false and assigns an error message to the passed OdString;
otherwise OdError with the error message is thrown.
*/
bool checkInternalConsistence(OdString* pFirstErrorDetected = NULL) const;
/** \details
Checks whether the body has coincident edges.
\returns true if the face has at least two coincident edges, or false otherwise.
*/
bool hasCoincidentEdges() const;
/** \details
Checks whether the body has coincident vertices.
\returns true if the face has at least two coincident vertices, or false otherwise.
*/
bool hasCoincidentVertices() const;
/** \details
Checks whether the body is empty.
\returns false if the body has at least one face, or true otherwise.
*/
bool isNull() const;
/** \details
Checks whether the body is closed (any face is connected to another one at any edge).
\returns true if the body is closed, or false otherwise.
*/
bool isClosed() const;
/** \details
Splits a single face with a plane while preserving topology.
\param pFace [in] Face to split.
\param pPlane [in] Splitting plane.
\param pNewOuter [in] Resulting outer faces.
\param pNewInner [in] Resulting inner faces.
*/
void splitFace(Face* pFace,
const OdGePlane& pPlane,
std::vector* pNewOuter = NULL,
std::vector* pNewInner = NULL);
////////////////////////////////////////////////////////////////
// Tags and flags
////////////////////////////////////////////////////////////////
/** \details
Resets vertex tags.
\param clearValue [in] New value to set.
*/
void clearVertexTags(TagType clearValue = 0);
/** \details
Resets body tags.
\param clearValue [in] New value to set.
*/
void clearSurfaceTags(TagType clearValue = 0);
/** \details
Resets edge tags.
\param clearValue [in] New value to set.
*/
void clearEdgeTags(TagType clearValue = 0);
/** \details
Resets face tags.
\param clearValue [in] New value to set.
*/
void clearFaceTags(TagType clearValue = 0);
/** \details
Resets face flags.
\param clearValue [in] New value to set.
*/
void clearFaceFlags(OdUInt32 clearValue = 0);
/** \details
Resets body tags.
\param clearValue [in] New value to set.
*/
inline void clearBodyTags(TagType clearValue = 0) { setTag(clearValue); }
/** \details
Gets the first tag.
\returns Tag value.
*/
TagType tag() const;
/** \details
Sets the first tag.
\param iTag [in] New tag value.
*/
void setTag(TagType iTag);
////////////////////////////////////////////////////////////////
// Geometric properties
////////////////////////////////////////////////////////////////
/** \details
Gets geometric extents.
\returns Calculated geometric extents as OdGeExtents3d.
*/
OdGeExtents3d interval() const;
/** \details
Calculates volume.
\returns Volume value.
*/
double volume() const;
////////////////////////////////////////////////////////////////
// Intersections
////////////////////////////////////////////////////////////////
/** \details
Gets a slice profile created by the specified plane.
\param rCutter [in] Cutting plane to slice the body.
\param rResult [out] Resulting profile.
\param bIncludeBoundary [in] true to include bounds in the resulting profile, false to exclude.
*/
void slice(const OdGePlane& rCutter,
Profile3D& rResult, bool bIncludeBoundary = true) const;
/** \details
Gets a slice half-body created by the specified plane.
\param rCutter [in] Cutting plane to slice the body.
\param result [out] Resulting body.
*/
void slice(const OdGePlane& rCutter, Body& result, TagType tagSection = 0) const;
/** \details
Intersects this body with the given line.
\param gLine [in] Line to intersect with.
\param aPoints [out] Intersection points array.
\param bSortResults [in] true to sort points behind their parameters on the line gLine.
\returns true if there are intersections, or false otherwise.
\remarks
There can be multiple equal intersections.
*/
bool intersectLine(const OdGeLinearEnt3d& gLine,
std::vector< OdGePoint3d >& aPoints, bool bSortResults = false) const;
////////////////////////////////////////////////////////////////
// Primitives
////////////////////////////////////////////////////////////////
/** \details
Creates a box.
\param ptOrigin [in] Origin.
\param vSizes [in] Three box sizes.
\returns Resulting body.
*/
static Body box(const OdGePoint3d& ptOrigin,
const OdGeVector3d& vSizes);
/** \details
Creates a pyramid.
\param rBase [in] Base profile (on XY plane).
\param ptApex [in] Pyramid apex.
\param deviation [in] Deviation parameters.
\returns Resulting body.
*/
static Body pyramid(const Profile2D& rBase,
const OdGePoint3d& ptApex,
const DeviationParams& deviation = FMGeGbl::gDefDev);
/** \details
Creates an extrusion.
\param rBase [in] Base profile (on XY plane).
\param vDir [in] Extrusion direction.
\param deviation [in] Deviation parameters.
\returns Resulting body.
*/
static Body extrusion(const Profile2D& rBase,
const OdGeVector3d& vDir,
const DeviationParams& deviation = FMGeGbl::gDefDev);
/** \details
Creates an extrusion.
\param rBase [in] Base profile (on XY plane).
\param rPath [in] Path specified in plane.
\param deviation [in] Deviation parameters.
\returns Resulting body.
*/
static Body extrusion(const Profile2D& rBase,
const Contour3D& rPath,
const DeviationParams& deviation = FMGeGbl::gDefDev);
/** \details
Creates an extrusion.
\param rBase [in] Base profile (on XY plane).
\param rPath [in] Path specified in space.
\param vNormal [in] Profile top in space.
\param deviation [in] Deviation parameters.
\returns Resulting body.
*/
static Body extrusion(const Profile2D& rBase,
const OdGePoint3dArray& rPath,
const OdGeVector3d& vNormal,
const DeviationParams& devDeviation = FMGeGbl::gDefDev);
/** \details
Creates an extrusion of a 2D profile along the vDir vector.
\param rBase [in] Base profile (on XY plane).
\param mBasePlane [in] Initial 3D plane of the profile as OdGeMatrix3d.
\param vDir [in] Extrusion direction and length.
\param deviation [in] Deviation parameters.
\returns Resulting body.
\remarks
The profile is placed into the 3D plane defined by the mBasePlane matrix
and then extruded along the vDir path of the extrusion.
vDir must be non-perpendicular to the mProfilePlane z-axis.
*/
static Body extrusion(const Profile2D& rBase,
const OdGeMatrix3d& mBasePlane,
const OdGeVector3d& vDir,
const DeviationParams& deviation = FMGeGbl::gDefDev);
/** \details
Creates a revolution body using a base profile, radius, height and deviation parameters.
\param rBase [in] Base profile (X - along height, Y - along radius).
\param dRadius [in] Radius.
\param dHeight [in] Height.
\param deviation [in] Deviation parameters.
\returns Resulting body.
*/
static Body revolution(const Profile2D& rBase,
double dRadius, double dHeight,
const DeviationParams& deviation = FMGeGbl::gDefDev);
/** \details
Creates a revolution body using a base profile, circle arc with revolution axis and angles, and deviation parameters.
\param base [in] Base profile (on XY plane).
\param revAxisAndAngles [in] Circle arc with specified revolution axis as normal and revolution angles.
\param deviation [in] Deviation parameters.
\param pBaseTransform [in] (Optional) Transform to be applied to the base profile while being revolved.
\returns Resulting body.
*/
static Body revolution(
const Profile2D& base,
const OdGeCircArc3d& revAxisAndAngles,
const DeviationParams& deviation = FMGeGbl::gDefDev,
const OdGeMatrix2d* pBaseTransform = NULL);
/** \details
Creates a revolution body using a base profile, revolution axis, position of the revolution axis,
start and end angles of revolution, and deviation parameters.
\param base [in] Base profile (on XY plane).
\param revAxis [in] Revolution axis.
\param axisPosition [in] Position of the revolution axis.
\param startAng [in] Start angle of revolution.
\param endAng [in] End angle of revolution.
\param deviation [in] Deviation parameters.
\returns Resulting body.
\remarks
If base profile is not closed, this makes boolean operations with the resulting body impossible.
*/
static Body revolution(
const Profile2D& base,
const OdGeVector3d& revAxis,
const OdGePoint3d& axisPosition,
double startAng,
double endAng,
const DeviationParams& deviation = FMGeGbl::gDefDev);
/** \details
Performs a boolean operation destroying both operands.
\param eOperation [in] Boolean operation type.
\param rOperandA [in] Operand A.
\param rOperandB [in] Operand B.
\param bOptimization [in] Optimization flag
\param tolMergePlane [in] Vector tolerance to check whether two faces are coplanar
\returns Resulting body.
*/
static Body boolOper(BooleanOperation eOperation,
Body& rOperandA, Body& rOperandB, bool bOptimization = false, double tolMergePlane = 0.);
/** \details
Creates a custom body from the specified definition arrays.
\param aVertices [in] Array of vertex points.
\param aFaceData [in] Array of integers describing the face definition based on the input vertex array.
\param aEdgeFlags [in] Edge flags array.
\param aFaceFlags [in] Face flags array.
\param aVertexFlags [in] Vertex flags array.
\param pFaceColors [in] Colors array of the faces.
\param pEdgeColors [in] Colors array of the edges.
\param pMappingCoords [in] The mapping coordinates array for every face.
\returns Resulting body.
\remarks
Only suitable for good input topology (without t-junctions).
The aFaceData is an array of faces, and each face is represented in it
by a sequence of numbers. The first number in the sequence
determines the number of vertices for the face and must be greater than or equal to 3.
The following numbers define the indices of vertices in aVertices.
*/
static Body createFromMesh(
const std::vector& aVertices,
const std::vector& aFaceData,
const std::vector* aFaceFlags = NULL,
const std::vector* aEdgeFlags = NULL,
const std::vector* aVertexFlags = NULL,
const std::vector* pFaceColors = NULL,
const std::vector* pEdgeColors = NULL,
const std::vector* pMappingCoords = NULL
);
/** \details
Creates triangles mesh representing this body.
\param mesh [out] The generated triangles mesh.
*/
void generateMesh(GeMesh::OdGeTrMesh& mesh) const;
////////////////////////////////////////////////////////////////
// Working with topological entities
////////////////////////////////////////////////////////////////
/** \details
Sets face and edge colors to the specified value.
\param iColor [in] New color value as OdUInt32.
*/
void setColor(OdUInt32 iColor);
/** \details
Adds a face.
\param pFace [in] Face to add.
\remarks
For internal use only.
*/
void addFace(Face* pFace);
/** \details
Removes a face.
\param pFace [in] Face to remove.
\remarks
For internal use only.
*/
void removeFace(Face* pFace);
/** \details
Removes and deletes a face.
\param pFace [in] Face to delete.
\remarks
For internal use only.
*/
void deleteFace(Face* pFace);
/** \details
Adds the specified surface to the body.
\param pSurface [in] Surface to add.
*/
void addSurface(Surface* pSurface);
/** \details
Adds the specified vertex to the body.
\param pVertex [in] Vertex to add.
*/
void addVertex(Vertex* pVertex);
/** \details
Adds a vertex.
\param pt [in] Vertex coordinates as OdGePoint3d.
\returns Pointer to the newly created vertex.
*/
Vertex* addVertex(const OdGePoint3d& pt);
/** \details
Adds a face.
\param pSurface [in] Surface to assign.
\returns Pointer to the newly created face.
*/
Face* addFace(Surface* pSurface = NULL);
/** \details
Gets a vertex count.
\returns Count of vertices as OdUInt32.
*/
OdUInt32 vertexCount() const;
/** \details
Counts and returns the number of edges.
\returns Edge count as OdUInt32.
*/
OdUInt32 countEdges() const;
/** \details
Gets the cached edge count.
\returns Cached edge count.
\remarks
The returned edge count is what was calculated in the most recent countEdges() call.
*/
OdUInt32 cachedEdgesCount() const;
/** \details
Gets a faces count.
\returns Count of faces as OdUInt32.
*/
OdUInt32 faceCount() const;
/** \details
Gets a surface count.
\returns Count of surfaces as OdUInt32.
*/
OdUInt32 surfaceCount() const;
/** \details
Gets a face list.
\returns Face list pointer.
*/
Face* faceList() const;
/** \details
Gets a vertex list.
\returns Vertex list pointer.
*/
Vertex* vertexList() const;
/** \details
Gets a surface list.
\returns Surface list pointer.
*/
Surface* surfaceList() const;
/** \details
Sets the pointer to the first vertex of the body.
\param pList [in] Vertex list pointer.
*/
void setVertexList(Vertex* pList);
/** \details
Sets the pointer to the first face of the body.
\param pList [in] Face list pointer.
*/
void setFaceList(Face* pList);
/** \details
Sets the pointer to the first surface of the body.
\param pList [in] Surface list pointer.
*/
void setSurfaceList(Surface* pList);
/** \details
Deletes surfaces that are not set to any face
*/
void deleteUnusedSurfaces();
/** \details
Sets the count of vertices to the specified number.
\param count [in] New vertex count.
\remarks
Use with setVertexList.
*/
void setVertexCount(OdUInt32 count);
/** \details
Sets the count of faces to the specified number.
\param count [in] New face count.
\remarks
Use with setFaceList.
*/
void setFaceCount(OdUInt32 count);
/** \details
Sets the count of surfaces to the specified number.
\param count [in] New surface count.
\remarks
Use with setVertexList.
*/
void setSurfaceCount(OdUInt32 count);
/** Empty body object. */
FMGEOMETRY_API_STATIC static const Body kEmpty;
/** \details
Destructor.
*/
~Body();
/** \details
Reduces the number of primitives (vertices and faces).
\param param [in] Simplification percent if positive, or tolerance if negative.
\remarks
All the faces will be converted to triangles first. The result will contain the number of triangles
according to given percent (for example, 10% of initial number). If param is negative, then the
resulting body will contain the minimum number of triangles to match the given max deviation
from initial mesh.
*/
void simplify(double param);
/** \details
Sets the property that Body has inner shell.
\param val [in] whether Body has inner shell
\remarks
For internal use. If Body has inner shell, it prevents it from being decomposed into lumps.
*/
void setHasInnerShell(bool val);
/** \details
Gets the property that Body has inner shell.
\returns Whether Body has inner shell.
*/
bool hasInnerShell() const;
#if 0
public:
void testCheckUnusedSurfaceData();
#endif
protected:
/** \details
Creates Body object with specified implementation object pointer.
\param pImpl [in] Implementation object pointer.
*/
explicit Body(class BodyImpl* pImpl);
private:
BodyImpl* m_pImpl; // Implementation object pointer.
//DOM-IGNORE-BEGIN
friend class Vertex;
friend class Face;
friend class Surface;
friend class BodyImpl;
friend class BodyCustom;
friend class BodyInternalConsistencyRestorer;
//DOM-IGNORE-END
};
/** \details
Creates shaded surfaces for the given Body.
\param aBody [inout] Body to process.
\param angleTol [in] The angle to detect the crease between faces.
\param bDetectSharpEdges [in] The flag to perform additional sharp edges detection for better quality.
\remarks
Shaded surfaces allow to calculate vertex normals for shaded rendering of the Body. This function
finds 'smooth' areas of the Body and marks them with the common shaded surface.
*/
FMGEOMETRY_API void MarkShadedSurfaces(Body& aBody, double angleTol, bool bDetectSharpEdges = false);
/** \details
Deletes all the shaded surfaces for the given Body.
\param aBody [inout] Body to process.
*/
FMGEOMETRY_API void ClearShadedSurfaces(Body& aBody);
/** \details
Merges together different shaded surfaces of the given Body. Replaces surfaces from the set with the first surface.
\param aBody [inout] Body to process.
\param shadedMergeData [in] The set of surfaces to be merged.
*/
void MergeShadedSurfaces(Body& aBody, const OdArray >& shadedMergeData);
}
#endif //__FMMDL_BODY_H__