mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-08-09 13:22:24 +03:00
Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
551d35ab93 | ||
|
3d21fe1aee | ||
|
2922a73ea7 | ||
|
e2d60d0f7f |
@@ -454,6 +454,7 @@ t TKRWMesh
|
||||
n RWGltf
|
||||
n RWMesh
|
||||
n RWObj
|
||||
n RWPly
|
||||
n DFBrowser
|
||||
n DFBrowserPane
|
||||
n DFBrowserPaneXDE
|
||||
|
@@ -996,7 +996,6 @@ void AIS_InteractiveContext::RecomputePrsOnly (const Handle(AIS_InteractiveObjec
|
||||
myMainVwr->Update();
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : RecomputeSelectionOnly
|
||||
//purpose :
|
||||
@@ -1008,20 +1007,9 @@ void AIS_InteractiveContext::RecomputeSelectionOnly (const Handle(AIS_Interactiv
|
||||
return;
|
||||
}
|
||||
|
||||
const Handle(AIS_GlobalStatus)* aStatus = myObjects.Seek (theIO);
|
||||
if (aStatus != NULL)
|
||||
{
|
||||
if (!myLastPicked.IsNull()
|
||||
&& myLastPicked->IsSameSelectable (theIO))
|
||||
{
|
||||
clearDynamicHighlight();
|
||||
myLastPicked.Nullify();
|
||||
}
|
||||
|
||||
unselectOwners (theIO);
|
||||
}
|
||||
|
||||
mgrSelector->RecomputeSelection (theIO);
|
||||
|
||||
const Handle(AIS_GlobalStatus)* aStatus = myObjects.Seek (theIO);
|
||||
if (aStatus == NULL
|
||||
|| theIO->DisplayStatus() != PrsMgr_DisplayStatus_Displayed)
|
||||
{
|
||||
|
@@ -147,7 +147,6 @@ public: //! @name object display management
|
||||
Standard_EXPORT void RemoveAll (const Standard_Boolean theToUpdateViewer);
|
||||
|
||||
//! Recomputes the seen parts presentation of the Object.
|
||||
//! The object will be also unhighlighted and removed from selection.
|
||||
//! If theAllModes equals true, all presentations are present in the object even if unseen.
|
||||
Standard_EXPORT void Redisplay (const Handle(AIS_InteractiveObject)& theIObj,
|
||||
const Standard_Boolean theToUpdateViewer,
|
||||
@@ -160,14 +159,13 @@ public: //! @name object display management
|
||||
const Standard_Boolean theToUpdateViewer);
|
||||
|
||||
//! Recomputes the displayed presentations, flags the others.
|
||||
//! Doesn't update selections.
|
||||
//! Doesn't update presentations.
|
||||
Standard_EXPORT void RecomputePrsOnly (const Handle(AIS_InteractiveObject)& theIObj,
|
||||
const Standard_Boolean theToUpdateViewer,
|
||||
const Standard_Boolean theAllModes = Standard_False);
|
||||
|
||||
//! Recomputes the active selections, flags the others.
|
||||
//! Doesn't update presentations.
|
||||
//! The object will be also unhighlighted and removed from selection.
|
||||
Standard_EXPORT void RecomputeSelectionOnly (const Handle(AIS_InteractiveObject)& anIObj);
|
||||
|
||||
//! Updates displayed interactive object by checking and recomputing its flagged as "to be recomputed" presentation and selection structures.
|
||||
|
307
src/BRepLib/BRepLib_PointCloudShape.cxx
Normal file
307
src/BRepLib/BRepLib_PointCloudShape.cxx
Normal file
@@ -0,0 +1,307 @@
|
||||
// Copyright (c) 2021 OPEN CASCADE SAS
|
||||
//
|
||||
// This file is part of Open CASCADE Technology software library.
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Lesser General Public License version 2.1 as published
|
||||
// by the Free Software Foundation, with special exception defined in the file
|
||||
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
|
||||
// distribution for complete text of the license and disclaimer of any warranty.
|
||||
//
|
||||
// Alternatively, this file may be used under the terms of Open CASCADE
|
||||
// commercial license or contractual agreement.
|
||||
|
||||
#include <BRepLib_PointCloudShape.hxx>
|
||||
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <BRepGProp.hxx>
|
||||
#include <BRepLib_ToolTriangulatedShape.hxx>
|
||||
#include <BRepTools.hxx>
|
||||
#include <BRepTopAdaptor_FClass2d.hxx>
|
||||
#include <Geom_Surface.hxx>
|
||||
#include <GProp_GProps.hxx>
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <gp_Vec.hxx>
|
||||
#include <Precision.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
|
||||
#include <random>
|
||||
|
||||
// =======================================================================
|
||||
// function : BRepLib_PointCloudShape
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
BRepLib_PointCloudShape::BRepLib_PointCloudShape (const TopoDS_Shape& theShape,
|
||||
const Standard_Real theTol)
|
||||
: myShape (theShape),
|
||||
myDist (0.0),
|
||||
myTol (theTol),
|
||||
myNbPoints (0)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : ~BRepLib_PointCloudShape
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
BRepLib_PointCloudShape::~BRepLib_PointCloudShape()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : NbPointsByDensity
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Standard_Integer BRepLib_PointCloudShape::NbPointsByDensity (const Standard_Real theDensity)
|
||||
{
|
||||
clear();
|
||||
Standard_Real aDensity = (theDensity < Precision::Confusion() ? computeDensity() : theDensity);
|
||||
if (aDensity < Precision::Confusion())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Standard_Integer aNbPoints = 0;
|
||||
for (TopExp_Explorer aExpF(myShape, TopAbs_FACE); aExpF.More(); aExpF.Next())
|
||||
{
|
||||
Standard_Real anArea = faceArea(aExpF.Current());
|
||||
|
||||
Standard_Integer aNbPnts = Max ((Standard_Integer)std::ceil(anArea / theDensity), 1);
|
||||
myFacePoints.Bind(aExpF.Current(), aNbPnts);
|
||||
aNbPoints+= aNbPnts;
|
||||
}
|
||||
return aNbPoints;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : GeneratePointsByDensity
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Standard_Boolean BRepLib_PointCloudShape::GeneratePointsByDensity (const Standard_Real theDensity)
|
||||
{
|
||||
if (myFacePoints.IsEmpty())
|
||||
{
|
||||
if (NbPointsByDensity (theDensity) == 0)
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
}
|
||||
|
||||
Standard_Integer aNbAdded = 0;
|
||||
for (TopExp_Explorer aExpF (myShape, TopAbs_FACE); aExpF.More(); aExpF.Next())
|
||||
{
|
||||
if (addDensityPoints (aExpF.Current()))
|
||||
{
|
||||
aNbAdded++;
|
||||
}
|
||||
}
|
||||
return (aNbAdded > 0);
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : GeneratePointsByTriangulation
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Standard_Boolean BRepLib_PointCloudShape::GeneratePointsByTriangulation()
|
||||
{
|
||||
clear();
|
||||
|
||||
Standard_Integer aNbAdded = 0;
|
||||
for (TopExp_Explorer aExpF (myShape, TopAbs_FACE); aExpF.More(); aExpF.Next())
|
||||
{
|
||||
if (addTriangulationPoints (aExpF.Current()))
|
||||
{
|
||||
aNbAdded++;
|
||||
}
|
||||
}
|
||||
return (aNbAdded > 0);
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : faceArea
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Standard_Real BRepLib_PointCloudShape::faceArea (const TopoDS_Shape& theShape)
|
||||
{
|
||||
Standard_Real anArea = 0.0;
|
||||
if (myFaceArea.Find (theShape, anArea))
|
||||
{
|
||||
return anArea;
|
||||
}
|
||||
|
||||
GProp_GProps aFaceProps;
|
||||
BRepGProp::SurfaceProperties (theShape, aFaceProps);
|
||||
anArea = aFaceProps.Mass();
|
||||
myFaceArea.Bind (theShape, anArea);
|
||||
return anArea;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : computeDensity
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Standard_Real BRepLib_PointCloudShape::computeDensity()
|
||||
{
|
||||
// at first step find the face with smallest area
|
||||
Standard_Real anAreaMin = Precision::Infinite();
|
||||
for (TopExp_Explorer aExpF (myShape, TopAbs_FACE); aExpF.More(); aExpF.Next())
|
||||
{
|
||||
Standard_Real anArea = faceArea (aExpF.Current());
|
||||
if (anArea < myTol * myTol)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (anArea < anAreaMin)
|
||||
{
|
||||
anAreaMin = anArea;
|
||||
}
|
||||
}
|
||||
return anAreaMin * 0.1;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : NbPointsByTriangulation
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Standard_Integer BRepLib_PointCloudShape::NbPointsByTriangulation() const
|
||||
{
|
||||
// at first step find the face with smallest area
|
||||
Standard_Integer aNbPoints = 0;
|
||||
for (TopExp_Explorer aExpF (myShape, TopAbs_FACE); aExpF.More(); aExpF.Next())
|
||||
{
|
||||
TopLoc_Location aLoc;
|
||||
Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation (TopoDS::Face (aExpF.Current()), aLoc);
|
||||
if (aTriangulation.IsNull())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
aNbPoints += aTriangulation->NbNodes();
|
||||
}
|
||||
return aNbPoints;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : addDensityPoints
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Standard_Boolean BRepLib_PointCloudShape::addDensityPoints (const TopoDS_Shape& theFace)
|
||||
{
|
||||
//addition of the points with specified density on the face by random way
|
||||
Standard_Integer aNbPnts = (myFacePoints.IsBound (theFace) ? myFacePoints.Find (theFace) : 0);
|
||||
if (aNbPnts == 0)
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
TopoDS_Face aFace = TopoDS::Face (theFace);
|
||||
Standard_Real anUMin = 0.0, anUMax = 0.0, aVMin = 0.0, aVMax = 0.0;
|
||||
BRepTools::UVBounds (aFace, anUMin, anUMax, aVMin, aVMax);
|
||||
BRepTopAdaptor_FClass2d aClassifier (aFace, Precision::Confusion());
|
||||
|
||||
TopLoc_Location aLoc = theFace.Location();
|
||||
const gp_Trsf& aTrsf = aLoc.Transformation();
|
||||
TopLoc_Location aLoc1;
|
||||
Handle(Geom_Surface) aSurf = BRep_Tool::Surface (aFace, aLoc1);
|
||||
if (aSurf.IsNull())
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
std::mt19937 aRandomGenerator(0);
|
||||
std::uniform_real_distribution<> anUDistrib(anUMin, anUMax);
|
||||
std::uniform_real_distribution<> aVDistrib (aVMin, aVMax);
|
||||
for (Standard_Integer nbCurPnts = 1; nbCurPnts <= aNbPnts;)
|
||||
{
|
||||
const Standard_Real aU = anUDistrib(aRandomGenerator);
|
||||
const Standard_Real aV = aVDistrib (aRandomGenerator);
|
||||
gp_Pnt2d aUVNode (aU, aV);
|
||||
const TopAbs_State aState = aClassifier.Perform (aUVNode);
|
||||
if (aState == TopAbs_OUT)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
nbCurPnts++;
|
||||
|
||||
gp_Pnt aP1;
|
||||
gp_Vec dU, dV;
|
||||
aSurf->D1 (aU, aV, aP1, dU, dV);
|
||||
|
||||
gp_Vec aNorm = dU ^ dV;
|
||||
if (aFace.Orientation() == TopAbs_REVERSED)
|
||||
{
|
||||
aNorm.Reverse();
|
||||
}
|
||||
const Standard_Real aNormMod = aNorm.Magnitude();
|
||||
if (aNormMod > gp::Resolution())
|
||||
{
|
||||
aNorm /= aNormMod;
|
||||
}
|
||||
if (myDist > Precision::Confusion())
|
||||
{
|
||||
std::uniform_real_distribution<> aDistanceDistrib (0.0, myDist);
|
||||
gp_XYZ aDeflPoint = aP1.XYZ() + aNorm.XYZ() * aDistanceDistrib (aRandomGenerator);
|
||||
aP1.SetXYZ (aDeflPoint);
|
||||
}
|
||||
aP1.Transform (aTrsf);
|
||||
if (aNormMod > gp::Resolution())
|
||||
{
|
||||
aNorm = gp_Dir (aNorm).Transformed (aTrsf);
|
||||
}
|
||||
addPoint (aP1, aNorm, aUVNode, aFace);
|
||||
}
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : addTriangulationPoints
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Standard_Boolean BRepLib_PointCloudShape::addTriangulationPoints (const TopoDS_Shape& theFace)
|
||||
{
|
||||
TopLoc_Location aLoc;
|
||||
TopoDS_Face aFace = TopoDS::Face (theFace);
|
||||
Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation (aFace, aLoc);
|
||||
if (aTriangulation.IsNull())
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
TopLoc_Location aLoc1;
|
||||
Handle(Geom_Surface) aSurf = BRep_Tool::Surface (aFace, aLoc1);
|
||||
const gp_Trsf& aTrsf = aLoc.Transformation();
|
||||
|
||||
BRepLib_ToolTriangulatedShape::ComputeNormals (aFace, aTriangulation);
|
||||
Standard_Boolean aHasUVNode = aTriangulation->HasUVNodes();
|
||||
for (Standard_Integer aNodeIter = 1; aNodeIter <= aTriangulation->NbNodes(); ++aNodeIter)
|
||||
{
|
||||
gp_Pnt aP1 = aTriangulation->Node (aNodeIter);
|
||||
gp_Dir aNormal = aTriangulation->Normal(aNodeIter);
|
||||
if (!aLoc.IsIdentity())
|
||||
{
|
||||
aP1 .Transform (aTrsf);
|
||||
aNormal.Transform (aTrsf);
|
||||
}
|
||||
|
||||
const gp_Pnt2d anUVNode = aHasUVNode ? aTriangulation->UVNode (aNodeIter) : gp_Pnt2d();
|
||||
addPoint (aP1, aNormal, anUVNode, aFace);
|
||||
}
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : clear
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
void BRepLib_PointCloudShape::clear()
|
||||
{
|
||||
myFaceArea.Clear();
|
||||
myFacePoints.Clear();
|
||||
}
|
116
src/BRepLib/BRepLib_PointCloudShape.hxx
Normal file
116
src/BRepLib/BRepLib_PointCloudShape.hxx
Normal file
@@ -0,0 +1,116 @@
|
||||
// Copyright (c) 2021 OPEN CASCADE SAS
|
||||
//
|
||||
// This file is part of Open CASCADE Technology software library.
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Lesser General Public License version 2.1 as published
|
||||
// by the Free Software Foundation, with special exception defined in the file
|
||||
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
|
||||
// distribution for complete text of the license and disclaimer of any warranty.
|
||||
//
|
||||
// Alternatively, this file may be used under the terms of Open CASCADE
|
||||
// commercial license or contractual agreement.
|
||||
|
||||
#ifndef _BRepLib_PointCloudShape_HeaderFile
|
||||
#define _BRepLib_PointCloudShape_HeaderFile
|
||||
|
||||
#include <TopTools_DataMapOfShapeInteger.hxx>
|
||||
#include <TopTools_DataMapOfShapeReal.hxx>
|
||||
#include <Quantity_Color.hxx>
|
||||
#include <Precision.hxx>
|
||||
|
||||
//! This tool is intended to get points from shape with specified distance from shape along normal.
|
||||
//! Can be used to simulation of points obtained in result of laser scan of shape.
|
||||
//! There are 2 ways for generation points by shape:
|
||||
//! 1. Generation points with specified density
|
||||
//! 2. Generation points using triangulation Nodes
|
||||
//! Generation of points by density using the GeneratePointsByDensity() function is not thread safe.
|
||||
class BRepLib_PointCloudShape
|
||||
{
|
||||
public:
|
||||
|
||||
DEFINE_STANDARD_ALLOC
|
||||
|
||||
//! Constructor initialized by shape
|
||||
Standard_EXPORT BRepLib_PointCloudShape (const TopoDS_Shape& theShape = TopoDS_Shape(),
|
||||
const Standard_Real theTol = Precision::Confusion());
|
||||
|
||||
//! Virtual destructor
|
||||
Standard_EXPORT virtual ~BRepLib_PointCloudShape();
|
||||
|
||||
//! Return loaded shape.
|
||||
const TopoDS_Shape& Shape() const { return myShape; }
|
||||
|
||||
//! Set shape.
|
||||
void SetShape (const TopoDS_Shape& theShape) { myShape = theShape; }
|
||||
|
||||
//! Return tolerance.
|
||||
Standard_Real Tolerance() const { return myTol; }
|
||||
|
||||
//! Set tolerance.
|
||||
void SetTolerance (Standard_Real theTol) { myTol = theTol; }
|
||||
|
||||
//! Returns value of the distance to define deflection of points from shape along normal to shape; 0.0 by default.
|
||||
Standard_Real GetDistance() const { return myDist; }
|
||||
|
||||
//! Sets value of the distance to define deflection of points from shape along normal to shape.
|
||||
//! Negative values of theDist parameter are ignored.
|
||||
void SetDistance (const Standard_Real theDist) { myDist = theDist; }
|
||||
|
||||
//! Returns size of the point cloud for specified density.
|
||||
Standard_EXPORT Standard_Integer NbPointsByDensity (const Standard_Real theDensity = 0.0);
|
||||
|
||||
//! Returns size of the point cloud for using triangulation.
|
||||
Standard_EXPORT Standard_Integer NbPointsByTriangulation() const;
|
||||
|
||||
//! Computes points with specified density for initial shape.
|
||||
//! If parameter Density is equal to 0 then density will be computed automatically by criterion:
|
||||
//! - 10 points per minimal unreduced face area.
|
||||
//!
|
||||
//! Note: this function should not be called from concurrent threads without external lock.
|
||||
Standard_EXPORT Standard_Boolean GeneratePointsByDensity (const Standard_Real theDensity = 0.0);
|
||||
|
||||
//! Get points from triangulation existing in the shape.
|
||||
Standard_EXPORT Standard_Boolean GeneratePointsByTriangulation();
|
||||
|
||||
protected:
|
||||
|
||||
//! Compute area of the specified face.
|
||||
Standard_EXPORT Standard_Real faceArea (const TopoDS_Shape& theShape);
|
||||
|
||||
//! Computes default density points per face.
|
||||
Standard_EXPORT Standard_Real computeDensity();
|
||||
|
||||
//! Adds points to face in accordance with the specified density randomly in the specified range [0, Dist].
|
||||
Standard_EXPORT Standard_Boolean addDensityPoints (const TopoDS_Shape& theFace);
|
||||
|
||||
//! Adds points to face by nodes of the existing triangulation randomly in the specified range [0, Dist].
|
||||
Standard_EXPORT Standard_Boolean addTriangulationPoints (const TopoDS_Shape& theFace);
|
||||
|
||||
protected:
|
||||
|
||||
//! Method to clear maps.
|
||||
Standard_EXPORT virtual void clear();
|
||||
|
||||
//! Method to add point, normal to surface in this point and face for which point computed.
|
||||
//! @param[in] thePoint 3D point on the surface
|
||||
//! @param[in] theNorm surface normal at this point
|
||||
//! @param[in] theUV surface UV parameters
|
||||
//! @param[in] theFace surface (face) definition
|
||||
Standard_EXPORT virtual void addPoint (const gp_Pnt& thePoint,
|
||||
const gp_Vec& theNorm,
|
||||
const gp_Pnt2d& theUV,
|
||||
const TopoDS_Shape& theFace) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
TopoDS_Shape myShape;
|
||||
Standard_Real myDist;
|
||||
Standard_Real myTol;
|
||||
TopTools_DataMapOfShapeReal myFaceArea;
|
||||
TopTools_DataMapOfShapeInteger myFacePoints;
|
||||
Standard_Integer myNbPoints;
|
||||
|
||||
};
|
||||
|
||||
#endif // _BRepLib_PointCloudShape_HeaderFile
|
83
src/BRepLib/BRepLib_ToolTriangulatedShape.cxx
Normal file
83
src/BRepLib/BRepLib_ToolTriangulatedShape.cxx
Normal file
@@ -0,0 +1,83 @@
|
||||
// Copyright (c) 2021 OPEN CASCADE SAS
|
||||
//
|
||||
// This file is part of Open CASCADE Technology software library.
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Lesser General Public License version 2.1 as published
|
||||
// by the Free Software Foundation, with special exception defined in the file
|
||||
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
|
||||
// distribution for complete text of the license and disclaimer of any warranty.
|
||||
//
|
||||
// Alternatively, this file may be used under the terms of Open CASCADE
|
||||
// commercial license or contractual agreement.
|
||||
|
||||
#include <BRepLib_ToolTriangulatedShape.hxx>
|
||||
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <GeomLib.hxx>
|
||||
#include <Poly.hxx>
|
||||
#include <Poly_Connect.hxx>
|
||||
#include <Precision.hxx>
|
||||
#include <TopLoc_Location.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
|
||||
// =======================================================================
|
||||
// function : ComputeNormals
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
void BRepLib_ToolTriangulatedShape::ComputeNormals (const TopoDS_Face& theFace,
|
||||
const Handle(Poly_Triangulation)& theTris,
|
||||
Poly_Connect& thePolyConnect)
|
||||
{
|
||||
if (theTris.IsNull()
|
||||
|| theTris->HasNormals())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// take in face the surface location
|
||||
const TopoDS_Face aZeroFace = TopoDS::Face (theFace.Located (TopLoc_Location()));
|
||||
Handle(Geom_Surface) aSurf = BRep_Tool::Surface (aZeroFace);
|
||||
if (!theTris->HasUVNodes() || aSurf.IsNull())
|
||||
{
|
||||
// compute normals by averaging triangulation normals sharing the same vertex
|
||||
Poly::ComputeNormals (theTris);
|
||||
return;
|
||||
}
|
||||
|
||||
const Standard_Real aTol = Precision::Confusion();
|
||||
Standard_Integer aTri[3];
|
||||
gp_Dir aNorm;
|
||||
theTris->AddNormals();
|
||||
for (Standard_Integer aNodeIter = 1; aNodeIter <= theTris->NbNodes(); ++aNodeIter)
|
||||
{
|
||||
// try to retrieve normal from real surface first, when UV coordinates are available
|
||||
if (GeomLib::NormEstim (aSurf, theTris->UVNode (aNodeIter), aTol, aNorm) > 1)
|
||||
{
|
||||
if (thePolyConnect.Triangulation() != theTris)
|
||||
{
|
||||
thePolyConnect.Load (theTris);
|
||||
}
|
||||
|
||||
// compute flat normals
|
||||
gp_XYZ eqPlan (0.0, 0.0, 0.0);
|
||||
for (thePolyConnect.Initialize (aNodeIter); thePolyConnect.More(); thePolyConnect.Next())
|
||||
{
|
||||
theTris->Triangle (thePolyConnect.Value()).Get (aTri[0], aTri[1], aTri[2]);
|
||||
const gp_XYZ v1 (theTris->Node (aTri[1]).Coord() - theTris->Node (aTri[0]).Coord());
|
||||
const gp_XYZ v2 (theTris->Node (aTri[2]).Coord() - theTris->Node (aTri[1]).Coord());
|
||||
const gp_XYZ vv = v1 ^ v2;
|
||||
const Standard_Real aMod = vv.Modulus();
|
||||
if (aMod >= aTol)
|
||||
{
|
||||
eqPlan += vv / aMod;
|
||||
}
|
||||
}
|
||||
const Standard_Real aModMax = eqPlan.Modulus();
|
||||
aNorm = (aModMax > aTol) ? gp_Dir (eqPlan) : gp::DZ();
|
||||
}
|
||||
|
||||
theTris->SetNormal (aNodeIter, aNorm);
|
||||
}
|
||||
}
|
50
src/BRepLib/BRepLib_ToolTriangulatedShape.hxx
Normal file
50
src/BRepLib/BRepLib_ToolTriangulatedShape.hxx
Normal file
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) 2021 OPEN CASCADE SAS
|
||||
//
|
||||
// This file is part of Open CASCADE Technology software library.
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Lesser General Public License version 2.1 as published
|
||||
// by the Free Software Foundation, with special exception defined in the file
|
||||
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
|
||||
// distribution for complete text of the license and disclaimer of any warranty.
|
||||
//
|
||||
// Alternatively, this file may be used under the terms of Open CASCADE
|
||||
// commercial license or contractual agreement.
|
||||
|
||||
#ifndef _BrepLib_ToolTriangulatedShape_HeaderFile
|
||||
#define _BrepLib_ToolTriangulatedShape_HeaderFile
|
||||
|
||||
#include <Poly_Connect.hxx>
|
||||
#include <Poly_Triangulation.hxx>
|
||||
|
||||
class TopoDS_Face;
|
||||
class Poly_Triangulation;
|
||||
|
||||
//! Provides methods for calculating normals to Poly_Triangulation of TopoDS_Face.
|
||||
class BRepLib_ToolTriangulatedShape
|
||||
{
|
||||
public:
|
||||
|
||||
//! Computes nodal normals for Poly_Triangulation structure using UV coordinates and surface.
|
||||
//! Does nothing if triangulation already defines normals.
|
||||
//! @param[in] theFace the face
|
||||
//! @param[in] theTris the definition of a face triangulation
|
||||
static void ComputeNormals (const TopoDS_Face& theFace,
|
||||
const Handle(Poly_Triangulation)& theTris)
|
||||
{
|
||||
Poly_Connect aPolyConnect;
|
||||
ComputeNormals (theFace, theTris, aPolyConnect);
|
||||
}
|
||||
|
||||
//! Computes nodal normals for Poly_Triangulation structure using UV coordinates and surface.
|
||||
//! Does nothing if triangulation already defines normals.
|
||||
//! @param[in] theFace the face
|
||||
//! @param[in] theTris the definition of a face triangulation
|
||||
//! @param[in,out] thePolyConnect optional, initialized tool for exploring triangulation
|
||||
Standard_EXPORT static void ComputeNormals (const TopoDS_Face& theFace,
|
||||
const Handle(Poly_Triangulation)& theTris,
|
||||
Poly_Connect& thePolyConnect);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
@@ -30,8 +30,12 @@ BRepLib_MakeVertex.hxx
|
||||
BRepLib_MakeWire.cxx
|
||||
BRepLib_MakeWire.hxx
|
||||
BRepLib_MakeWire_1.cxx
|
||||
BRepLib_PointCloudShape.hxx
|
||||
BRepLib_PointCloudShape.cxx
|
||||
BRepLib_ShapeModification.hxx
|
||||
BRepLib_ShellError.hxx
|
||||
BRepLib_ToolTriangulatedShape.hxx
|
||||
BRepLib_ToolTriangulatedShape.cxx
|
||||
BRepLib_ValidateEdge.cxx
|
||||
BRepLib_ValidateEdge.hxx
|
||||
BRepLib_WireError.hxx
|
||||
|
@@ -48,7 +48,8 @@ BRepMesh_IncrementalMesh::BRepMesh_IncrementalMesh( const TopoDS_Shape& theSh
|
||||
const Standard_Real theLinDeflection,
|
||||
const Standard_Boolean isRelative,
|
||||
const Standard_Real theAngDeflection,
|
||||
const Standard_Boolean isInParallel)
|
||||
const Standard_Boolean isInParallel,
|
||||
const Message_ProgressRange& theRange)
|
||||
: myModified(Standard_False),
|
||||
myStatus(IMeshData_NoError)
|
||||
{
|
||||
@@ -58,7 +59,7 @@ BRepMesh_IncrementalMesh::BRepMesh_IncrementalMesh( const TopoDS_Shape& theSh
|
||||
myParameters.InParallel = isInParallel;
|
||||
|
||||
myShape = theShape;
|
||||
Perform();
|
||||
Perform(theRange);
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
|
@@ -43,7 +43,8 @@ public: //! @name mesher API
|
||||
const Standard_Real theLinDeflection,
|
||||
const Standard_Boolean isRelative = Standard_False,
|
||||
const Standard_Real theAngDeflection = 0.5,
|
||||
const Standard_Boolean isInParallel = Standard_False);
|
||||
const Standard_Boolean isInParallel = Standard_False,
|
||||
const Message_ProgressRange& theRange = Message_ProgressRange());
|
||||
|
||||
//! Constructor.
|
||||
//! Automatically calls method Perform.
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#include <DrawTrSurf.hxx>
|
||||
#include <Message.hxx>
|
||||
#include <Message_PrinterOStream.hxx>
|
||||
#include <Message_PrinterSystemLog.hxx>
|
||||
#include <NCollection_IndexedMap.hxx>
|
||||
#include <OSD.hxx>
|
||||
#include <OSD_Thread.hxx>
|
||||
|
4
src/RWPly/FILES
Normal file
4
src/RWPly/FILES
Normal file
@@ -0,0 +1,4 @@
|
||||
RWPly_CafWriter.cxx
|
||||
RWPly_CafWriter.hxx
|
||||
RWPly_PlyWriterContext.cxx
|
||||
RWPly_PlyWriterContext.hxx
|
302
src/RWPly/RWPly_CafWriter.cxx
Normal file
302
src/RWPly/RWPly_CafWriter.cxx
Normal file
@@ -0,0 +1,302 @@
|
||||
// Copyright (c) 2022 OPEN CASCADE SAS
|
||||
//
|
||||
// This file is part of Open CASCADE Technology software library.
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Lesser General Public License version 2.1 as published
|
||||
// by the Free Software Foundation, with special exception defined in the file
|
||||
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
|
||||
// distribution for complete text of the license and disclaimer of any warranty.
|
||||
//
|
||||
// Alternatively, this file may be used under the terms of Open CASCADE
|
||||
// commercial license or contractual agreement.
|
||||
|
||||
#include <RWPly_CafWriter.hxx>
|
||||
|
||||
#include <Message.hxx>
|
||||
#include <Message_LazyProgressScope.hxx>
|
||||
#include <OSD_Path.hxx>
|
||||
#include <RWMesh_FaceIterator.hxx>
|
||||
#include <RWMesh_MaterialMap.hxx>
|
||||
#include <RWPly_PlyWriterContext.hxx>
|
||||
#include <Standard_CLocaleSentry.hxx>
|
||||
#include <TDocStd_Document.hxx>
|
||||
#include <TDataStd_Name.hxx>
|
||||
#include <XCAFDoc_DocumentTool.hxx>
|
||||
#include <XCAFDoc_ShapeTool.hxx>
|
||||
#include <XCAFPrs_DocumentExplorer.hxx>
|
||||
|
||||
IMPLEMENT_STANDARD_RTTIEXT(RWPly_CafWriter, Standard_Transient)
|
||||
|
||||
//================================================================
|
||||
// Function : Constructor
|
||||
// Purpose :
|
||||
//================================================================
|
||||
RWPly_CafWriter::RWPly_CafWriter (const TCollection_AsciiString& theFile)
|
||||
: myFile (theFile),
|
||||
myIsDoublePrec (false),
|
||||
myHasNormals (true),
|
||||
myHasColors (true),
|
||||
myHasTexCoords (false),
|
||||
myHasPartId (true),
|
||||
myHasFaceId (false)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
//================================================================
|
||||
// Function : Destructor
|
||||
// Purpose :
|
||||
//================================================================
|
||||
RWPly_CafWriter::~RWPly_CafWriter()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
//================================================================
|
||||
// Function : toSkipFaceMesh
|
||||
// Purpose :
|
||||
//================================================================
|
||||
Standard_Boolean RWPly_CafWriter::toSkipFaceMesh (const RWMesh_FaceIterator& theFaceIter)
|
||||
{
|
||||
return theFaceIter.IsEmptyMesh();
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : Perform
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
bool RWPly_CafWriter::Perform (const Handle(TDocStd_Document)& theDocument,
|
||||
const TColStd_IndexedDataMapOfStringString& theFileInfo,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
TDF_LabelSequence aRoots;
|
||||
Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool (theDocument->Main());
|
||||
aShapeTool->GetFreeShapes (aRoots);
|
||||
return Perform (theDocument, aRoots, NULL, theFileInfo, theProgress);
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : Perform
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
bool RWPly_CafWriter::Perform (const Handle(TDocStd_Document)& theDocument,
|
||||
const TDF_LabelSequence& theRootLabels,
|
||||
const TColStd_MapOfAsciiString* theLabelFilter,
|
||||
const TColStd_IndexedDataMapOfStringString& theFileInfo,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
TCollection_AsciiString aFolder, aFileName, aFullFileNameBase, aShortFileNameBase, aFileExt;
|
||||
OSD_Path::FolderAndFileFromPath (myFile, aFolder, aFileName);
|
||||
OSD_Path::FileNameAndExtension (aFileName, aShortFileNameBase, aFileExt);
|
||||
|
||||
Standard_Real aLengthUnit = 1.;
|
||||
if (XCAFDoc_DocumentTool::GetLengthUnit(theDocument, aLengthUnit))
|
||||
{
|
||||
myCSTrsf.SetInputLengthUnit(aLengthUnit);
|
||||
}
|
||||
|
||||
if (theRootLabels.IsEmpty()
|
||||
|| (theLabelFilter != NULL && theLabelFilter->IsEmpty()))
|
||||
{
|
||||
Message::SendFail ("Nothing to export into PLY file");
|
||||
return false;
|
||||
}
|
||||
|
||||
Standard_Integer aNbNodesAll = 0, aNbElemsAll = 0;
|
||||
Standard_Real aNbPEntities = 0; // steps for progress range
|
||||
for (XCAFPrs_DocumentExplorer aDocExplorer (theDocument, theRootLabels, XCAFPrs_DocumentExplorerFlags_OnlyLeafNodes);
|
||||
aDocExplorer.More(); aDocExplorer.Next())
|
||||
{
|
||||
const XCAFPrs_DocumentNode& aDocNode = aDocExplorer.Current();
|
||||
if (theLabelFilter != NULL
|
||||
&& !theLabelFilter->Contains (aDocNode.Id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, aDocNode.Location, true, aDocNode.Style); aFaceIter.More(); aFaceIter.Next())
|
||||
{
|
||||
if (toSkipFaceMesh (aFaceIter))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
addFaceInfo (aFaceIter, aNbNodesAll, aNbElemsAll);
|
||||
aNbPEntities += aNbNodesAll + aNbElemsAll;
|
||||
}
|
||||
}
|
||||
if (aNbNodesAll == 0)
|
||||
{
|
||||
Message::SendFail ("No mesh data to save");
|
||||
return false;
|
||||
}
|
||||
|
||||
Standard_CLocaleSentry aLocaleSentry;
|
||||
RWPly_PlyWriterContext aPlyCtx;
|
||||
aPlyCtx.SetDoublePrecision (myIsDoublePrec);
|
||||
aPlyCtx.SetNormals (myHasNormals);
|
||||
aPlyCtx.SetColors (myHasColors);
|
||||
aPlyCtx.SetTexCoords (myHasTexCoords);
|
||||
aPlyCtx.SetSurfaceId (myHasPartId || myHasFaceId);
|
||||
if (!aPlyCtx.Open (myFile)
|
||||
|| !aPlyCtx.WriteHeader (aNbNodesAll, aNbElemsAll, theFileInfo))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// simple global progress sentry
|
||||
const Standard_Real aPatchStep = 2048.0;
|
||||
Message_LazyProgressScope aPSentry (theProgress, "PLY export", aNbPEntities, aPatchStep);
|
||||
|
||||
bool isDone = true;
|
||||
for (Standard_Integer aStepIter = 0; aStepIter < 2; ++aStepIter)
|
||||
{
|
||||
aPlyCtx.SetSurfaceId (0);
|
||||
for (XCAFPrs_DocumentExplorer aDocExplorer (theDocument, theRootLabels, XCAFPrs_DocumentExplorerFlags_OnlyLeafNodes);
|
||||
aDocExplorer.More() && !aPSentry.IsAborted(); aDocExplorer.Next())
|
||||
{
|
||||
const XCAFPrs_DocumentNode& aDocNode = aDocExplorer.Current();
|
||||
if (theLabelFilter != NULL
|
||||
&& !theLabelFilter->Contains (aDocNode.Id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (myHasPartId)
|
||||
{
|
||||
aPlyCtx.SetSurfaceId (aPlyCtx.SurfaceId() + 1);
|
||||
}
|
||||
if (!writeShape (aPlyCtx, aPSentry, aStepIter, aDocNode.RefLabel, aDocNode.Location, aDocNode.Style))
|
||||
{
|
||||
isDone = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const bool isClosed = aPlyCtx.Close();
|
||||
if (isDone && !isClosed)
|
||||
{
|
||||
Message::SendFail (TCollection_AsciiString ("Failed to write PLY file\n") + myFile);
|
||||
return false;
|
||||
}
|
||||
return isDone && !aPSentry.IsAborted();
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : addFaceInfo
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
void RWPly_CafWriter::addFaceInfo (const RWMesh_FaceIterator& theFace,
|
||||
Standard_Integer& theNbNodes,
|
||||
Standard_Integer& theNbElems)
|
||||
{
|
||||
theNbNodes += theFace.NbNodes();
|
||||
theNbElems += theFace.NbTriangles();
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : writeShape
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
bool RWPly_CafWriter::writeShape (RWPly_PlyWriterContext& theWriter,
|
||||
Message_LazyProgressScope& thePSentry,
|
||||
const Standard_Integer theWriteStep,
|
||||
const TDF_Label& theLabel,
|
||||
const TopLoc_Location& theParentTrsf,
|
||||
const XCAFPrs_Style& theParentStyle)
|
||||
{
|
||||
for (RWMesh_FaceIterator aFaceIter (theLabel, theParentTrsf, true, theParentStyle); aFaceIter.More() && !thePSentry.IsAborted(); aFaceIter.Next())
|
||||
{
|
||||
if (toSkipFaceMesh (aFaceIter))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (theWriteStep == 0
|
||||
&& !writeNodes (theWriter, thePSentry, aFaceIter))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (theWriteStep == 1
|
||||
&& !writeIndices (theWriter, thePSentry, aFaceIter))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : writeNodes
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
bool RWPly_CafWriter::writeNodes (RWPly_PlyWriterContext& theWriter,
|
||||
Message_LazyProgressScope& thePSentry,
|
||||
const RWMesh_FaceIterator& theFace)
|
||||
{
|
||||
const Standard_Integer aNodeUpper = theFace.NodeUpper();
|
||||
Graphic3d_Vec3 aNormVec;
|
||||
Graphic3d_Vec2 aTexVec;
|
||||
Graphic3d_Vec4ub aColorVec (255);
|
||||
if (theFace.HasFaceColor())
|
||||
{
|
||||
//Graphic3d_Vec4 aColorF = Quantity_ColorRGBA::Convert_LinearRGB_To_sRGB (theFace.FaceColor());
|
||||
Graphic3d_Vec4 aColorF = theFace.FaceColor();
|
||||
aColorVec.SetValues ((unsigned char )int(aColorF.r() * 255.0f),
|
||||
(unsigned char )int(aColorF.g() * 255.0f),
|
||||
(unsigned char )int(aColorF.b() * 255.0f),
|
||||
(unsigned char )int(aColorF.a() * 255.0f));
|
||||
}
|
||||
for (Standard_Integer aNodeIter = theFace.NodeLower(); aNodeIter <= aNodeUpper && thePSentry.More(); ++aNodeIter, thePSentry.Next())
|
||||
{
|
||||
gp_XYZ aNode = theFace.NodeTransformed (aNodeIter).XYZ();
|
||||
myCSTrsf.TransformPosition (aNode);
|
||||
if (theFace.HasNormals())
|
||||
{
|
||||
gp_Dir aNorm = theFace.NormalTransformed (aNodeIter);
|
||||
aNormVec.SetValues ((float )aNorm.X(), (float )aNorm.Y(), (float )aNorm.Z());
|
||||
myCSTrsf.TransformNormal (aNormVec);
|
||||
}
|
||||
if (theFace.HasTexCoords())
|
||||
{
|
||||
const gp_Pnt2d aUV = theFace.NodeTexCoord (aNodeIter);
|
||||
aTexVec.SetValues ((float )aUV.X(), (float )aUV.Y());
|
||||
}
|
||||
|
||||
if (!theWriter.WriteVertex (aNode, aNormVec, aTexVec, aColorVec))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : writeIndices
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
bool RWPly_CafWriter::writeIndices (RWPly_PlyWriterContext& theWriter,
|
||||
Message_LazyProgressScope& thePSentry,
|
||||
const RWMesh_FaceIterator& theFace)
|
||||
{
|
||||
if (myHasFaceId)
|
||||
{
|
||||
theWriter.SetSurfaceId (theWriter.SurfaceId() + 1);
|
||||
}
|
||||
|
||||
const Standard_Integer anElemLower = theFace.ElemLower();
|
||||
const Standard_Integer anElemUpper = theFace.ElemUpper();
|
||||
for (Standard_Integer anElemIter = anElemLower; anElemIter <= anElemUpper && thePSentry.More(); ++anElemIter, thePSentry.Next())
|
||||
{
|
||||
const Poly_Triangle aTri = theFace.TriangleOriented (anElemIter);
|
||||
if (!theWriter.WriteTriangle (Graphic3d_Vec3i (aTri(1), aTri(2), aTri(3)) - Graphic3d_Vec3i (anElemLower)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
theWriter.SetVertexOffset (theWriter.VertexOffset() + theFace.NbNodes());
|
||||
return true;
|
||||
}
|
198
src/RWPly/RWPly_CafWriter.hxx
Normal file
198
src/RWPly/RWPly_CafWriter.hxx
Normal file
@@ -0,0 +1,198 @@
|
||||
// Copyright (c) 2022 OPEN CASCADE SAS
|
||||
//
|
||||
// This file is part of Open CASCADE Technology software library.
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Lesser General Public License version 2.1 as published
|
||||
// by the Free Software Foundation, with special exception defined in the file
|
||||
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
|
||||
// distribution for complete text of the license and disclaimer of any warranty.
|
||||
//
|
||||
// Alternatively, this file may be used under the terms of Open CASCADE
|
||||
// commercial license or contractual agreement.
|
||||
|
||||
#ifndef _RWPly_CafWriter_HeaderFiler
|
||||
#define _RWPly_CafWriter_HeaderFiler
|
||||
|
||||
#include <TColStd_IndexedDataMapOfStringString.hxx>
|
||||
#include <TColStd_MapOfAsciiString.hxx>
|
||||
#include <TDF_LabelSequence.hxx>
|
||||
#include <TopTools_ShapeMapHasher.hxx>
|
||||
#include <RWMesh_CoordinateSystemConverter.hxx>
|
||||
#include <XCAFPrs_Style.hxx>
|
||||
|
||||
#include <memory>
|
||||
|
||||
class Message_ProgressRange;
|
||||
class RWMesh_FaceIterator;
|
||||
class TDocStd_Document;
|
||||
|
||||
class Message_LazyProgressScope;
|
||||
class RWPly_PlyWriterContext;
|
||||
|
||||
//! PLY writer context from XCAF document.
|
||||
class RWPly_CafWriter : public Standard_Transient
|
||||
{
|
||||
DEFINE_STANDARD_RTTIEXT(RWPly_CafWriter, Standard_Transient)
|
||||
public:
|
||||
|
||||
//! Main constructor.
|
||||
//! @param[in] theFile path to output PLY file
|
||||
Standard_EXPORT RWPly_CafWriter (const TCollection_AsciiString& theFile);
|
||||
|
||||
//! Destructor.
|
||||
Standard_EXPORT virtual ~RWPly_CafWriter();
|
||||
|
||||
//! Return transformation from OCCT to PLY coordinate system.
|
||||
const RWMesh_CoordinateSystemConverter& CoordinateSystemConverter() const { return myCSTrsf; }
|
||||
|
||||
//! Return transformation from OCCT to PLY coordinate system.
|
||||
RWMesh_CoordinateSystemConverter& ChangeCoordinateSystemConverter() { return myCSTrsf; }
|
||||
|
||||
//! Set transformation from OCCT to PLY coordinate system.
|
||||
void SetCoordinateSystemConverter (const RWMesh_CoordinateSystemConverter& theConverter) { myCSTrsf = theConverter; }
|
||||
|
||||
//! Return default material definition to be used for nodes with only color defined.
|
||||
const XCAFPrs_Style& DefaultStyle() const { return myDefaultStyle; }
|
||||
|
||||
//! Set default material definition to be used for nodes with only color defined.
|
||||
void SetDefaultStyle (const XCAFPrs_Style& theStyle) { myDefaultStyle = theStyle; }
|
||||
|
||||
public:
|
||||
|
||||
//! Return TRUE if vertex position should be stored with double floating point precision; FALSE by default.
|
||||
bool IsDoublePrecision() const { return myIsDoublePrec; }
|
||||
|
||||
//! Set if vertex position should be stored with double floating point precision.
|
||||
void SetDoublePrecision (bool theDoublePrec) { myIsDoublePrec = theDoublePrec; }
|
||||
|
||||
//! Return TRUE if normals should be written; TRUE by default.
|
||||
bool HasNormals() const { return myHasNormals; }
|
||||
|
||||
//! Set if normals are defined.
|
||||
void SetNormals (const bool theHasNormals) { myHasNormals = theHasNormals; }
|
||||
|
||||
//! Return TRUE if UV / texture coordinates should be written; FALSE by default.
|
||||
bool HasTexCoords() const { return myHasTexCoords; }
|
||||
|
||||
//! Set if UV / texture coordinates should be written.
|
||||
void SetTexCoords (const bool theHasTexCoords) { myHasTexCoords = theHasTexCoords; }
|
||||
|
||||
//! Return TRUE if point colors should be written; TRUE by default.
|
||||
bool HasColors() const { return myHasColors; }
|
||||
|
||||
//! Set if point colors should be written.
|
||||
void SetColors (bool theToWrite) { myHasColors = theToWrite; }
|
||||
|
||||
//! Return TRUE if part Id should be written as element attribute; TRUE by default.
|
||||
bool HasPartId() const { return myHasPartId; }
|
||||
|
||||
//! Set if part Id should be written as element attribute; FALSE by default.
|
||||
//! Cannot be combined with HasFaceId().
|
||||
void SetPartId (bool theSurfId)
|
||||
{
|
||||
myHasPartId = theSurfId;
|
||||
myHasFaceId = myHasFaceId && !myHasPartId;
|
||||
}
|
||||
|
||||
//! Return TRUE if face Id should be written as element attribute; FALSE by default.
|
||||
bool HasFaceId() const { return myHasFaceId; }
|
||||
|
||||
//! Set if face Id should be written as element attribute; FALSE by default.
|
||||
//! Cannot be combined with HasPartId().
|
||||
void SetFaceId (bool theSurfId)
|
||||
{
|
||||
myHasFaceId = theSurfId;
|
||||
myHasPartId = myHasPartId && !myHasFaceId;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
//! Write PLY file and associated MTL material file.
|
||||
//! Triangulation data should be precomputed within shapes!
|
||||
//! @param[in] theDocument input document
|
||||
//! @param[in] theRootLabels list of root shapes to export
|
||||
//! @param[in] theLabelFilter optional filter with document nodes to export,
|
||||
//! with keys defined by XCAFPrs_DocumentExplorer::DefineChildId() and filled recursively
|
||||
//! (leaves and parent assembly nodes at all levels);
|
||||
//! when not NULL, all nodes not included into the map will be ignored
|
||||
//! @param[in] theFileInfo map with file metadata to put into PLY header section
|
||||
//! @param[in] theProgress optional progress indicator
|
||||
//! @return FALSE on file writing failure
|
||||
Standard_EXPORT virtual bool Perform (const Handle(TDocStd_Document)& theDocument,
|
||||
const TDF_LabelSequence& theRootLabels,
|
||||
const TColStd_MapOfAsciiString* theLabelFilter,
|
||||
const TColStd_IndexedDataMapOfStringString& theFileInfo,
|
||||
const Message_ProgressRange& theProgress);
|
||||
|
||||
//! Write PLY file and associated MTL material file.
|
||||
//! Triangulation data should be precomputed within shapes!
|
||||
//! @param[in] theDocument input document
|
||||
//! @param[in] theFileInfo map with file metadata to put into PLY header section
|
||||
//! @param[in] theProgress optional progress indicator
|
||||
//! @return FALSE on file writing failure
|
||||
Standard_EXPORT virtual bool Perform (const Handle(TDocStd_Document)& theDocument,
|
||||
const TColStd_IndexedDataMapOfStringString& theFileInfo,
|
||||
const Message_ProgressRange& theProgress);
|
||||
|
||||
protected:
|
||||
|
||||
//! Return TRUE if face mesh should be skipped (e.g. because it is invalid or empty).
|
||||
Standard_EXPORT virtual Standard_Boolean toSkipFaceMesh (const RWMesh_FaceIterator& theFaceIter);
|
||||
|
||||
//! Collect face triangulation info.
|
||||
//! @param[in] theFace face to process
|
||||
//! @param[in,out] theNbNodes overall number of triangulation nodes (should be appended)
|
||||
//! @param[in,out] theNbElems overall number of triangulation elements (should be appended)
|
||||
Standard_EXPORT virtual void addFaceInfo (const RWMesh_FaceIterator& theFace,
|
||||
Standard_Integer& theNbNodes,
|
||||
Standard_Integer& theNbElems);
|
||||
|
||||
//! Write the shape.
|
||||
//! @param[in] theWriter PLY writer context
|
||||
//! @param[in] thePSentry progress sentry
|
||||
//! @param[in] theWriteStep export step, 0 for vertex attributes, 1 for elements
|
||||
//! @param[in] theLabel document label to process
|
||||
//! @param[in] theParentTrsf parent node transformation
|
||||
//! @param[in] theParentStyle parent node style
|
||||
Standard_EXPORT virtual bool writeShape (RWPly_PlyWriterContext& theWriter,
|
||||
Message_LazyProgressScope& thePSentry,
|
||||
const Standard_Integer theWriteStep,
|
||||
const TDF_Label& theLabel,
|
||||
const TopLoc_Location& theParentTrsf,
|
||||
const XCAFPrs_Style& theParentStyle);
|
||||
|
||||
//! Write face triangle vertices and attributes.
|
||||
//! @param[in] theWriter PLY writer context
|
||||
//! @param[in] thePSentry progress sentry
|
||||
//! @param[in] theFace current face
|
||||
//! @return FALSE on writing file error
|
||||
Standard_EXPORT virtual bool writeNodes (RWPly_PlyWriterContext& theWriter,
|
||||
Message_LazyProgressScope& thePSentry,
|
||||
const RWMesh_FaceIterator& theFace);
|
||||
|
||||
//! Write face triangles indices.
|
||||
//! @param[in] theWriter PLY writer context
|
||||
//! @param[in] thePSentry progress sentry
|
||||
//! @param[in] theFace current face
|
||||
//! @return FALSE on writing file error
|
||||
Standard_EXPORT virtual bool writeIndices (RWPly_PlyWriterContext& theWriter,
|
||||
Message_LazyProgressScope& thePSentry,
|
||||
const RWMesh_FaceIterator& theFace);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
TCollection_AsciiString myFile; //!< output PLY file
|
||||
RWMesh_CoordinateSystemConverter myCSTrsf; //!< transformation from OCCT to PLY coordinate system
|
||||
XCAFPrs_Style myDefaultStyle; //!< default material definition to be used for nodes with only color defined
|
||||
Standard_Boolean myIsDoublePrec;
|
||||
Standard_Boolean myHasNormals;
|
||||
Standard_Boolean myHasColors;
|
||||
Standard_Boolean myHasTexCoords;
|
||||
Standard_Boolean myHasPartId;
|
||||
Standard_Boolean myHasFaceId;
|
||||
|
||||
};
|
||||
|
||||
#endif // _RWPly_CafWriter_HeaderFiler
|
324
src/RWPly/RWPly_PlyWriterContext.cxx
Normal file
324
src/RWPly/RWPly_PlyWriterContext.cxx
Normal file
@@ -0,0 +1,324 @@
|
||||
// Copyright (c) 2022 OPEN CASCADE SAS
|
||||
//
|
||||
// This file is part of Open CASCADE Technology software library.
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Lesser General Public License version 2.1 as published
|
||||
// by the Free Software Foundation, with special exception defined in the file
|
||||
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
|
||||
// distribution for complete text of the license and disclaimer of any warranty.
|
||||
//
|
||||
// Alternatively, this file may be used under the terms of Open CASCADE
|
||||
// commercial license or contractual agreement.
|
||||
|
||||
#include <RWPly_PlyWriterContext.hxx>
|
||||
|
||||
#include <Message.hxx>
|
||||
#include <NCollection_IndexedMap.hxx>
|
||||
#include <OSD_FileSystem.hxx>
|
||||
|
||||
// =======================================================================
|
||||
// function : splitLines
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
static void splitLines (const TCollection_AsciiString& theString,
|
||||
NCollection_IndexedMap<TCollection_AsciiString>& theLines)
|
||||
{
|
||||
if (theString.IsEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Standard_Integer aLineFrom = 1;
|
||||
for (Standard_Integer aCharIter = 1;; ++aCharIter)
|
||||
{
|
||||
const char aChar = theString.Value (aCharIter);
|
||||
if (aChar != '\r'
|
||||
&& aChar != '\n'
|
||||
&& aCharIter != theString.Length())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (aLineFrom != aCharIter)
|
||||
{
|
||||
TCollection_AsciiString aLine = theString.SubString (aLineFrom, aCharIter);
|
||||
aLine.RightAdjust();
|
||||
theLines.Add (aLine);
|
||||
}
|
||||
|
||||
if (aCharIter == theString.Length())
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (aChar == '\r'
|
||||
&& theString.Value (aCharIter + 1) == '\n')
|
||||
{
|
||||
// CRLF
|
||||
++aCharIter;
|
||||
}
|
||||
aLineFrom = aCharIter + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// Function : RWPly_PlyWriterContext
|
||||
// Purpose :
|
||||
// ================================================================
|
||||
RWPly_PlyWriterContext::RWPly_PlyWriterContext()
|
||||
: myNbHeaderVerts (0),
|
||||
myNbHeaderElems (0),
|
||||
myNbVerts (0),
|
||||
myNbElems (0),
|
||||
mySurfId (0),
|
||||
myVertOffset (0),
|
||||
myIsDoublePrec (false),
|
||||
myHasNormals (false),
|
||||
myHasColors (false),
|
||||
myHasTexCoords (false),
|
||||
myHasSurfId (false)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// Function : ~RWPly_PlyWriterContext
|
||||
// Purpose :
|
||||
// ================================================================
|
||||
RWPly_PlyWriterContext::~RWPly_PlyWriterContext()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// Function : Open
|
||||
// Purpose :
|
||||
// ================================================================
|
||||
bool RWPly_PlyWriterContext::Open (const TCollection_AsciiString& theName,
|
||||
const std::shared_ptr<std::ostream>& theStream)
|
||||
{
|
||||
myName = theName;
|
||||
myNbHeaderVerts = myNbHeaderElems = 0;
|
||||
myNbVerts = myNbElems = 0;
|
||||
if (theStream.get() != nullptr)
|
||||
{
|
||||
myStream = theStream;
|
||||
return true;
|
||||
}
|
||||
|
||||
const Handle(OSD_FileSystem)& aFileSystem = OSD_FileSystem::DefaultFileSystem();
|
||||
myStream = aFileSystem->OpenOStream (theName, std::ios::out | std::ios::binary);
|
||||
if (myStream.get() == NULL || !myStream->good())
|
||||
{
|
||||
myStream.reset();
|
||||
Message::SendFail() << "Error: file cannot be created\n" << theName;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// Function : Close
|
||||
// Purpose :
|
||||
// ================================================================
|
||||
bool RWPly_PlyWriterContext::Close (bool theIsAborted)
|
||||
{
|
||||
if (myStream.get() == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
myStream->flush();
|
||||
bool aResult = myStream->good();
|
||||
if (!aResult)
|
||||
{
|
||||
Message::SendFail() << "Error: file cannot be written\n" << myName;
|
||||
}
|
||||
else if (!theIsAborted)
|
||||
{
|
||||
if (myNbVerts != myNbHeaderVerts)
|
||||
{
|
||||
Message::SendFail() << "Error: written less number of vertices (" << myNbVerts << ") than specified in PLY header (" << myNbHeaderVerts << ")";
|
||||
}
|
||||
else if (myNbElems != myNbHeaderElems)
|
||||
{
|
||||
Message::SendFail() << "Error: written less number of elements (" << myNbElems << ") than specified in PLY header (" << myNbHeaderElems << ")";
|
||||
}
|
||||
}
|
||||
myStream.reset();
|
||||
return aResult;
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// Function : WriteHeader
|
||||
// Purpose :
|
||||
// ================================================================
|
||||
bool RWPly_PlyWriterContext::WriteHeader (const Standard_Integer theNbNodes,
|
||||
const Standard_Integer theNbElems,
|
||||
const TColStd_IndexedDataMapOfStringString& theFileInfo)
|
||||
{
|
||||
if (myStream.get() == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
myNbHeaderVerts = theNbNodes;
|
||||
myNbHeaderElems = theNbElems;
|
||||
*myStream << "ply\n"
|
||||
"format ascii 1.0\n"
|
||||
"comment Exported by Open CASCADE Technology [dev.opencascade.org]\n";
|
||||
for (TColStd_IndexedDataMapOfStringString::Iterator aKeyValueIter (theFileInfo); aKeyValueIter.More(); aKeyValueIter.Next())
|
||||
{
|
||||
NCollection_IndexedMap<TCollection_AsciiString> aKeyLines, aValLines;
|
||||
splitLines (aKeyValueIter.Key(), aKeyLines);
|
||||
splitLines (aKeyValueIter.Value(), aValLines);
|
||||
for (Standard_Integer aLineIter = 1; aLineIter <= aKeyLines.Extent(); ++aLineIter)
|
||||
{
|
||||
const TCollection_AsciiString& aLine = aKeyLines.FindKey (aLineIter);
|
||||
*myStream << (aLineIter > 1 ? "\n" : "") << "comment " << aLine;
|
||||
}
|
||||
*myStream << (!aKeyLines.IsEmpty() ? ":" : "comment ");
|
||||
for (Standard_Integer aLineIter = 1; aLineIter <= aValLines.Extent(); ++aLineIter)
|
||||
{
|
||||
const TCollection_AsciiString& aLine = aValLines.FindKey (aLineIter);
|
||||
*myStream << (aLineIter > 1 ? "\n" : "") << "comment " << aLine;
|
||||
}
|
||||
*myStream << "\n";
|
||||
}
|
||||
|
||||
*myStream << "element vertex " << theNbNodes<< "\n";
|
||||
if (myIsDoublePrec)
|
||||
{
|
||||
*myStream << "property double x\n"
|
||||
"property double y\n"
|
||||
"property double z\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
*myStream << "property float x\n"
|
||||
"property float y\n"
|
||||
"property float z\n";
|
||||
}
|
||||
if (myHasNormals)
|
||||
{
|
||||
*myStream << "property float nx\n"
|
||||
"property float ny\n"
|
||||
"property float nz\n";
|
||||
}
|
||||
if (myHasTexCoords)
|
||||
{
|
||||
*myStream << "property float s\n"
|
||||
"property float t\n";
|
||||
}
|
||||
if (myHasColors)
|
||||
{
|
||||
*myStream << "property uchar red\n"
|
||||
"property uchar green\n"
|
||||
"property uchar blue\n";
|
||||
}
|
||||
|
||||
if (theNbElems > 0)
|
||||
{
|
||||
*myStream << "element face " << theNbElems << "\n"
|
||||
"property list uchar uint vertex_indices\n";
|
||||
if (myHasSurfId)
|
||||
{
|
||||
*myStream << "property uint SurfaceID\n";
|
||||
}
|
||||
}
|
||||
|
||||
*myStream << "end_header\n";
|
||||
return myStream->good();
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// Function : WriteVertex
|
||||
// Purpose :
|
||||
// ================================================================
|
||||
bool RWPly_PlyWriterContext::WriteVertex (const gp_Pnt& thePoint,
|
||||
const Graphic3d_Vec3& theNorm,
|
||||
const Graphic3d_Vec2& theUV,
|
||||
const Graphic3d_Vec4ub& theColor)
|
||||
{
|
||||
if (myStream.get() == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (myIsDoublePrec)
|
||||
{
|
||||
*myStream << (double )thePoint.X() << " " << (double )thePoint.Y() << " " << (double )thePoint.Z();
|
||||
}
|
||||
else
|
||||
{
|
||||
*myStream << (float )thePoint.X() << " " << (float )thePoint.Y() << " " << (float )thePoint.Z();
|
||||
}
|
||||
if (myHasNormals)
|
||||
{
|
||||
*myStream << " " << (float )theNorm.x() << " " << (float )theNorm.y() << " " << (float )theNorm.z();
|
||||
}
|
||||
if (myHasTexCoords)
|
||||
{
|
||||
*myStream << " " << (float )theUV.x() << " " << (float )theUV.y();
|
||||
}
|
||||
if (myHasColors)
|
||||
{
|
||||
*myStream << " " << (int )theColor.r() << " " << (int )theColor.g() << " " << (int )theColor.b();
|
||||
}
|
||||
*myStream << "\n";
|
||||
if (++myNbVerts > myNbHeaderVerts)
|
||||
{
|
||||
throw Standard_OutOfRange ("RWPly_PlyWriterContext::WriteVertex() - number of vertices is greater than defined");
|
||||
}
|
||||
return myStream->good();
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// Function : WriteTriangle
|
||||
// Purpose :
|
||||
// ================================================================
|
||||
bool RWPly_PlyWriterContext::WriteTriangle (const Graphic3d_Vec3i& theTri)
|
||||
{
|
||||
if (myStream.get() == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const Graphic3d_Vec3i aTri = Graphic3d_Vec3i(myVertOffset) + theTri;
|
||||
*myStream << "3 " << aTri[0] << " " << aTri[1] << " " << aTri[2];
|
||||
if (myHasSurfId)
|
||||
{
|
||||
*myStream << " " << mySurfId;
|
||||
}
|
||||
*myStream << "\n";
|
||||
if (++myNbElems > myNbHeaderElems)
|
||||
{
|
||||
throw Standard_OutOfRange ("RWPly_PlyWriterContext::WriteTriangle() - number of elements is greater than defined");
|
||||
}
|
||||
return myStream->good();
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// Function : WriteQuad
|
||||
// Purpose :
|
||||
// ================================================================
|
||||
bool RWPly_PlyWriterContext::WriteQuad (const Graphic3d_Vec4i& theQuad)
|
||||
{
|
||||
if (myStream.get() == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const Graphic3d_Vec4i aQuad = Graphic3d_Vec4i(myVertOffset) + theQuad;
|
||||
*myStream << "4 " << aQuad[0] << " " << aQuad[1] << " " << aQuad[2] << " " << aQuad[3];
|
||||
if (myHasSurfId)
|
||||
{
|
||||
*myStream << " " << mySurfId;
|
||||
}
|
||||
*myStream << "\n";
|
||||
if (++myNbElems > myNbHeaderElems)
|
||||
{
|
||||
throw Standard_OutOfRange ("RWPly_PlyWriterContext::WriteQuad() - number of elements is greater than defined");
|
||||
}
|
||||
return myStream->good();
|
||||
}
|
142
src/RWPly/RWPly_PlyWriterContext.hxx
Normal file
142
src/RWPly/RWPly_PlyWriterContext.hxx
Normal file
@@ -0,0 +1,142 @@
|
||||
// Copyright (c) 2022 OPEN CASCADE SAS
|
||||
//
|
||||
// This file is part of Open CASCADE Technology software library.
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Lesser General Public License version 2.1 as published
|
||||
// by the Free Software Foundation, with special exception defined in the file
|
||||
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
|
||||
// distribution for complete text of the license and disclaimer of any warranty.
|
||||
//
|
||||
// Alternatively, this file may be used under the terms of Open CASCADE
|
||||
// commercial license or contractual agreement.
|
||||
|
||||
#ifndef _RWPly_PlyWriterContext_HeaderFiler
|
||||
#define _RWPly_PlyWriterContext_HeaderFiler
|
||||
|
||||
#include <Graphic3d_Vec.hxx>
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <TCollection_AsciiString.hxx>
|
||||
#include <TColStd_IndexedDataMapOfStringString.hxx>
|
||||
|
||||
#include <memory>
|
||||
|
||||
//! Auxiliary low-level tool writing PLY file.
|
||||
class RWPly_PlyWriterContext
|
||||
{
|
||||
public:
|
||||
|
||||
//! Empty constructor.
|
||||
Standard_EXPORT RWPly_PlyWriterContext();
|
||||
|
||||
//! Destructor, will emit error message if file was not closed.
|
||||
Standard_EXPORT ~RWPly_PlyWriterContext();
|
||||
|
||||
public: //! @name vertex attributes parameters
|
||||
|
||||
//! Return TRUE if vertex position should be stored with double floating point precision; FALSE by default.
|
||||
bool IsDoublePrecision() const { return myIsDoublePrec; }
|
||||
|
||||
//! Set if vertex position should be stored with double floating point precision.
|
||||
void SetDoublePrecision (bool theDoublePrec) { myIsDoublePrec = theDoublePrec; }
|
||||
|
||||
//! Return TRUE if normals should be written as vertex attribute; FALSE by default.
|
||||
bool HasNormals() const { return myHasNormals; }
|
||||
|
||||
//! Set if normals should be written.
|
||||
void SetNormals (const bool theHasNormals) { myHasNormals = theHasNormals; }
|
||||
|
||||
//! Return TRUE if UV / texture coordinates should be written as vertex attribute; FALSE by default.
|
||||
bool HasTexCoords() const { return myHasTexCoords; }
|
||||
|
||||
//! Set if UV / texture coordinates should be written.
|
||||
void SetTexCoords (const bool theHasTexCoords) { myHasTexCoords = theHasTexCoords; }
|
||||
|
||||
//! Return TRUE if point colors should be written as vertex attribute; FALSE by default.
|
||||
bool HasColors() const { return myHasColors; }
|
||||
|
||||
//! Set if point colors should be written.
|
||||
void SetColors (bool theToWrite) { myHasColors = theToWrite; }
|
||||
|
||||
public: //! @name element attributes parameters
|
||||
|
||||
//! Return TRUE if surface Id should be written as element attribute; FALSE by default.
|
||||
bool HasSurfaceId() const { return myHasSurfId; }
|
||||
|
||||
//! Set if surface Id should be written as element attribute; FALSE by default.
|
||||
void SetSurfaceId (bool theSurfId) { myHasSurfId = theSurfId; }
|
||||
|
||||
public: //! @name writing into file
|
||||
|
||||
//! Return TRUE if file has been opened.
|
||||
bool IsOpened() const { return myStream.get() != nullptr; }
|
||||
|
||||
//! Open file for writing.
|
||||
Standard_EXPORT bool Open (const TCollection_AsciiString& theName,
|
||||
const std::shared_ptr<std::ostream>& theStream = std::shared_ptr<std::ostream>());
|
||||
|
||||
//! Write the header.
|
||||
//! @param[in] theNbNodes number of vertex nodes
|
||||
//! @param[in] theNbElems number of mesh elements
|
||||
//! @param[in] theFileInfo optional comments
|
||||
Standard_EXPORT bool WriteHeader (const Standard_Integer theNbNodes,
|
||||
const Standard_Integer theNbElems,
|
||||
const TColStd_IndexedDataMapOfStringString& theFileInfo);
|
||||
|
||||
//! Write single point with all attributes.
|
||||
//! @param[in] thePoint 3D point coordinates
|
||||
//! @param[in] theNorm surface normal direction at the point
|
||||
//! @param[in] theUV surface/texture UV coordinates
|
||||
//! @param[in] theColor RGB color values
|
||||
Standard_EXPORT bool WriteVertex (const gp_Pnt& thePoint,
|
||||
const Graphic3d_Vec3& theNorm,
|
||||
const Graphic3d_Vec2& theUV,
|
||||
const Graphic3d_Vec4ub& theColor);
|
||||
|
||||
//! Return number of written vertices.
|
||||
Standard_Integer NbWrittenVertices() const { return myNbVerts; }
|
||||
|
||||
//! Return vertex offset to be applied to element indices; 0 by default.
|
||||
Standard_Integer VertexOffset() const { return myVertOffset; }
|
||||
|
||||
//! Set vertex offset to be applied to element indices.
|
||||
void SetVertexOffset (Standard_Integer theOffset) { myVertOffset = theOffset; }
|
||||
|
||||
//! Return surface id to write with element; 0 by default.
|
||||
Standard_Integer SurfaceId() const { return mySurfId; }
|
||||
|
||||
//! Set surface id to write with element.
|
||||
void SetSurfaceId (Standard_Integer theSurfId) { mySurfId = theSurfId; }
|
||||
|
||||
//! Writing a triangle.
|
||||
Standard_EXPORT bool WriteTriangle (const Graphic3d_Vec3i& theTri);
|
||||
|
||||
//! Writing a quad.
|
||||
Standard_EXPORT bool WriteQuad (const Graphic3d_Vec4i& theQuad);
|
||||
|
||||
//! Return number of written elements.
|
||||
Standard_Integer NbWrittenElements() const { return myNbElems; }
|
||||
|
||||
//! Correctly close the file.
|
||||
//! @return FALSE in case of writing error
|
||||
Standard_EXPORT bool Close (bool theIsAborted = false);
|
||||
|
||||
private:
|
||||
|
||||
std::shared_ptr<std::ostream> myStream;
|
||||
TCollection_AsciiString myName;
|
||||
Standard_Integer myNbHeaderVerts;
|
||||
Standard_Integer myNbHeaderElems;
|
||||
Standard_Integer myNbVerts;
|
||||
Standard_Integer myNbElems;
|
||||
Standard_Integer mySurfId;
|
||||
Standard_Integer myVertOffset;
|
||||
bool myIsDoublePrec;
|
||||
bool myHasNormals;
|
||||
bool myHasColors;
|
||||
bool myHasTexCoords;
|
||||
bool myHasSurfId;
|
||||
|
||||
};
|
||||
|
||||
#endif // _RWPly_PlyWriterContext_HeaderFiler
|
@@ -147,12 +147,6 @@ Handle(Poly_Triangulation) RWStl::ReadFile (const OSD_Path& theFile,
|
||||
Handle(Poly_Triangulation) RWStl::ReadBinary (const OSD_Path& theFile,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
OSD_File aFile(theFile);
|
||||
if (!aFile.Exists())
|
||||
{
|
||||
return Handle(Poly_Triangulation)();
|
||||
}
|
||||
|
||||
TCollection_AsciiString aPath;
|
||||
theFile.SystemName (aPath);
|
||||
|
||||
@@ -179,31 +173,24 @@ Handle(Poly_Triangulation) RWStl::ReadBinary (const OSD_Path& theFile,
|
||||
Handle(Poly_Triangulation) RWStl::ReadAscii (const OSD_Path& theFile,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
OSD_File aFile (theFile);
|
||||
if (!aFile.Exists())
|
||||
{
|
||||
return Handle(Poly_Triangulation)();
|
||||
}
|
||||
|
||||
TCollection_AsciiString aPath;
|
||||
theFile.SystemName (aPath);
|
||||
|
||||
std::filebuf aBuf;
|
||||
OSD_OpenStream (aBuf, aPath, std::ios::in | std::ios::binary);
|
||||
if (!aBuf.is_open())
|
||||
const Handle(OSD_FileSystem)& aFileSystem = OSD_FileSystem::DefaultFileSystem();
|
||||
std::shared_ptr<std::istream> aStream = aFileSystem->OpenIStream (aPath, std::ios::in | std::ios::binary);
|
||||
if (aStream.get() == NULL)
|
||||
{
|
||||
return Handle(Poly_Triangulation)();
|
||||
}
|
||||
Standard_IStream aStream (&aBuf);
|
||||
|
||||
// get length of file to feed progress indicator
|
||||
aStream.seekg (0, aStream.end);
|
||||
std::streampos theEnd = aStream.tellg();
|
||||
aStream.seekg (0, aStream.beg);
|
||||
aStream->seekg (0, aStream->end);
|
||||
std::streampos theEnd = aStream->tellg();
|
||||
aStream->seekg (0, aStream->beg);
|
||||
|
||||
Reader aReader;
|
||||
Standard_ReadLineBuffer aBuffer (THE_BUFFER_SIZE);
|
||||
if (!aReader.ReadAscii (aStream, aBuffer, theEnd, theProgress))
|
||||
if (!aReader.ReadAscii (*aStream, aBuffer, theEnd, theProgress))
|
||||
{
|
||||
return Handle(Poly_Triangulation)();
|
||||
}
|
||||
@@ -351,7 +338,7 @@ Standard_Boolean RWStl::writeBinary (const Handle(Poly_Triangulation)& theMesh,
|
||||
FILE* theFile,
|
||||
const Message_ProgressRange& theProgress)
|
||||
{
|
||||
char aHeader[80] = "STL Exported by OpenCASCADE [www.opencascade.com]";
|
||||
char aHeader[80] = "STL Exported by Open CASCADE Technology [dev.opencascade.org]";
|
||||
if (fwrite (aHeader, 1, 80, theFile) != 80)
|
||||
{
|
||||
return Standard_False;
|
||||
|
@@ -18,24 +18,11 @@
|
||||
|
||||
#include <BRepBndLib.hxx>
|
||||
#include <BRepMesh_DiscretFactory.hxx>
|
||||
#include <BRepMesh_DiscretRoot.hxx>
|
||||
#include <BRepTools.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <GeomAbs_SurfaceType.hxx>
|
||||
#include <GeomLib.hxx>
|
||||
#include <gp_XYZ.hxx>
|
||||
#include <Poly.hxx>
|
||||
#include <Poly_Connect.hxx>
|
||||
#include <Poly_Triangulation.hxx>
|
||||
#include <Precision.hxx>
|
||||
#include <Prs3d.hxx>
|
||||
#include <Prs3d_Drawer.hxx>
|
||||
#include <TColgp_Array1OfPnt.hxx>
|
||||
#include <TColgp_Array1OfPnt2d.hxx>
|
||||
#include <TopAbs_Orientation.hxx>
|
||||
#include <TopLoc_Location.hxx>
|
||||
#include <TShort_HArray1OfShortReal.hxx>
|
||||
#include <TShort_Array1OfShortReal.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
@@ -132,66 +119,6 @@ Standard_Boolean StdPrs_ToolTriangulatedShape::IsClosed (const TopoDS_Shape& the
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : ComputeNormals
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
void StdPrs_ToolTriangulatedShape::ComputeNormals (const TopoDS_Face& theFace,
|
||||
const Handle(Poly_Triangulation)& theTris,
|
||||
Poly_Connect& thePolyConnect)
|
||||
{
|
||||
if (theTris.IsNull()
|
||||
|| theTris->HasNormals())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// take in face the surface location
|
||||
const TopoDS_Face aZeroFace = TopoDS::Face (theFace.Located (TopLoc_Location()));
|
||||
Handle(Geom_Surface) aSurf = BRep_Tool::Surface (aZeroFace);
|
||||
if (!theTris->HasUVNodes() || aSurf.IsNull())
|
||||
{
|
||||
// compute normals by averaging triangulation normals sharing the same vertex
|
||||
Poly::ComputeNormals (theTris);
|
||||
return;
|
||||
}
|
||||
|
||||
const Standard_Real aTol = Precision::Confusion();
|
||||
Standard_Integer aTri[3];
|
||||
gp_Dir aNorm;
|
||||
theTris->AddNormals();
|
||||
for (Standard_Integer aNodeIter = 1; aNodeIter <= theTris->NbNodes(); ++aNodeIter)
|
||||
{
|
||||
// try to retrieve normal from real surface first, when UV coordinates are available
|
||||
if (GeomLib::NormEstim (aSurf, theTris->UVNode (aNodeIter), aTol, aNorm) > 1)
|
||||
{
|
||||
if (thePolyConnect.Triangulation() != theTris)
|
||||
{
|
||||
thePolyConnect.Load (theTris);
|
||||
}
|
||||
|
||||
// compute flat normals
|
||||
gp_XYZ eqPlan (0.0, 0.0, 0.0);
|
||||
for (thePolyConnect.Initialize (aNodeIter); thePolyConnect.More(); thePolyConnect.Next())
|
||||
{
|
||||
theTris->Triangle (thePolyConnect.Value()).Get (aTri[0], aTri[1], aTri[2]);
|
||||
const gp_XYZ v1 (theTris->Node (aTri[1]).Coord() - theTris->Node (aTri[0]).Coord());
|
||||
const gp_XYZ v2 (theTris->Node (aTri[2]).Coord() - theTris->Node (aTri[1]).Coord());
|
||||
const gp_XYZ vv = v1 ^ v2;
|
||||
const Standard_Real aMod = vv.Modulus();
|
||||
if (aMod >= aTol)
|
||||
{
|
||||
eqPlan += vv / aMod;
|
||||
}
|
||||
}
|
||||
const Standard_Real aModMax = eqPlan.Modulus();
|
||||
aNorm = (aModMax > aTol) ? gp_Dir (eqPlan) : gp::DZ();
|
||||
}
|
||||
|
||||
theTris->SetNormal (aNodeIter, aNorm);
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : Normal
|
||||
//purpose :
|
||||
|
@@ -14,19 +14,13 @@
|
||||
#ifndef _StdPrs_ToolTriangulatedShape_HeaderFile
|
||||
#define _StdPrs_ToolTriangulatedShape_HeaderFile
|
||||
|
||||
#include <Poly_Connect.hxx>
|
||||
#include <Poly_Triangulation.hxx>
|
||||
#include <Prs3d_Drawer.hxx>
|
||||
#include <Standard.hxx>
|
||||
#include <Standard_Macro.hxx>
|
||||
#include <BRepLib_ToolTriangulatedShape.hxx>
|
||||
#include <TColgp_Array1OfDir.hxx>
|
||||
|
||||
class TopoDS_Face;
|
||||
class TopoDS_Shape;
|
||||
class Prs3d_Drawer;
|
||||
class Poly_Triangulation;
|
||||
|
||||
class StdPrs_ToolTriangulatedShape
|
||||
class StdPrs_ToolTriangulatedShape: public BRepLib_ToolTriangulatedShape
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -38,26 +32,6 @@ public:
|
||||
//! @return true if shape is closed manifold Solid or compound of such Solids. <br>
|
||||
Standard_EXPORT static Standard_Boolean IsClosed (const TopoDS_Shape& theShape);
|
||||
|
||||
//! Computes nodal normals for Poly_Triangulation structure using UV coordinates and surface.
|
||||
//! Does nothing if triangulation already defines normals.
|
||||
//! @param theFace [in] the face
|
||||
//! @param theTris [in] the definition of a face triangulation
|
||||
static void ComputeNormals (const TopoDS_Face& theFace,
|
||||
const Handle(Poly_Triangulation)& theTris)
|
||||
{
|
||||
Poly_Connect aPolyConnect;
|
||||
ComputeNormals (theFace, theTris, aPolyConnect);
|
||||
}
|
||||
|
||||
//! Computes nodal normals for Poly_Triangulation structure using UV coordinates and surface.
|
||||
//! Does nothing if triangulation already defines normals.
|
||||
//! @param theFace [in] the face
|
||||
//! @param theTris [in] the definition of a face triangulation
|
||||
//! @param thePolyConnect [in,out] optional, initialized tool for exploring triangulation
|
||||
Standard_EXPORT static void ComputeNormals (const TopoDS_Face& theFace,
|
||||
const Handle(Poly_Triangulation)& theTris,
|
||||
Poly_Connect& thePolyConnect);
|
||||
|
||||
//! Evaluate normals for a triangle of a face.
|
||||
//! @param[in] theFace the face.
|
||||
//! @param[in] thePolyConnect the definition of a face triangulation.
|
||||
|
@@ -14,22 +14,8 @@
|
||||
// Alternatively, this file may be used under the terms of Open CASCADE
|
||||
// commercial license or contractual agreement.
|
||||
|
||||
// StepFile_Read
|
||||
|
||||
// routine assurant l enchainement des operations de lecture d un fichier
|
||||
// STEP dans un StepModel, en fonction d une cle de reconnaissance
|
||||
// Retour de la fonction :
|
||||
// 0 si OK (le StepModel a ete charge)
|
||||
// -1 si abandon car fichier pas pu etre ouvert
|
||||
// 1 si erreur en cours de lecture
|
||||
|
||||
// Compilation conditionnelle : concerne les mesures de performances
|
||||
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
|
||||
#include <step.tab.hxx>
|
||||
#include <StepFile_Read.hxx>
|
||||
|
||||
#include <StepFile_ReadData.hxx>
|
||||
|
||||
#include <Interface_Check.hxx>
|
||||
@@ -49,9 +35,13 @@
|
||||
#include <Message.hxx>
|
||||
#include <Message_Messenger.hxx>
|
||||
|
||||
#include <OSD_OpenFile.hxx>
|
||||
#include <OSD_FileSystem.hxx>
|
||||
#include <OSD_Timer.hxx>
|
||||
|
||||
#include "step.tab.hxx"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef OCCT_DEBUG
|
||||
#define CHRONOMESURE
|
||||
#endif
|
||||
@@ -73,14 +63,15 @@ static Standard_Integer StepFile_Read (const char* theName,
|
||||
const Handle(StepData_FileRecognizer)& theRecogData)
|
||||
{
|
||||
// if stream is not provided, open file stream here
|
||||
std::istream *aStreamPtr = theIStream;
|
||||
std::ifstream aFileStream;
|
||||
if (!aStreamPtr) {
|
||||
OSD_OpenStream(aFileStream, theName, std::ios_base::in | std::ios_base::binary);
|
||||
aStreamPtr = &aFileStream;
|
||||
std::istream* aStreamPtr = theIStream;
|
||||
std::shared_ptr<std::istream> aFileStream;
|
||||
if (aStreamPtr == nullptr)
|
||||
{
|
||||
const Handle(OSD_FileSystem)& aFileSystem = OSD_FileSystem::DefaultFileSystem();
|
||||
aFileStream = aFileSystem->OpenIStream (theName, std::ios::in | std::ios::binary);
|
||||
aStreamPtr = aFileStream.get();
|
||||
}
|
||||
|
||||
if (aStreamPtr->fail())
|
||||
if (aStreamPtr == nullptr || aStreamPtr->fail())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
@@ -17,6 +17,9 @@
|
||||
#ifndef StepFile_Read_HeaderFile
|
||||
#define StepFile_Read_HeaderFile
|
||||
|
||||
#include <Standard_CString.hxx>
|
||||
#include <Standard_Type.hxx>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
class StepData_StepModel;
|
||||
|
@@ -1,3 +1,4 @@
|
||||
RWGltf
|
||||
RWMesh
|
||||
RWObj
|
||||
RWPly
|
||||
|
@@ -5238,8 +5238,6 @@ static int VDisplay2 (Draw_Interpretor& theDI,
|
||||
}
|
||||
}
|
||||
|
||||
// invalidate picking cache
|
||||
ViewerTest::CurrentEventManager()->ResetPreviousMoveTo();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -40,6 +40,7 @@
|
||||
#include <AIS_Shape.hxx>
|
||||
#include <AIS_DisplayMode.hxx>
|
||||
#include <AIS_PointCloud.hxx>
|
||||
#include <BRepLib_PointCloudShape.hxx>
|
||||
#include <TColStd_MapOfInteger.hxx>
|
||||
#include <ViewerTest_AutoUpdater.hxx>
|
||||
#include <ViewerTest_DoubleMapOfInteractiveAndName.hxx>
|
||||
@@ -6250,6 +6251,12 @@ static Standard_Integer VPointCloud (Draw_Interpretor& theDI,
|
||||
Standard_Integer theArgNum,
|
||||
const char** theArgs)
|
||||
{
|
||||
if (theArgNum < 2)
|
||||
{
|
||||
Message::SendFail ("Syntax error: wrong number of arguments");
|
||||
return 1;
|
||||
}
|
||||
|
||||
Handle(AIS_InteractiveContext) anAISContext = ViewerTest::GetAISContext();
|
||||
if (anAISContext.IsNull())
|
||||
{
|
||||
@@ -6257,83 +6264,114 @@ static Standard_Integer VPointCloud (Draw_Interpretor& theDI,
|
||||
return 1;
|
||||
}
|
||||
|
||||
// command to execute
|
||||
enum Command
|
||||
{
|
||||
CloudForShape, // generate point cloud for shape
|
||||
CloudSphere, // generate point cloud for generic sphere
|
||||
Unknow
|
||||
};
|
||||
TCollection_AsciiString aName;
|
||||
TopoDS_Shape aShape;
|
||||
|
||||
// count number of non-optional command arguments
|
||||
Command aCmd = Unknow;
|
||||
Standard_Integer aCmdArgs = 0;
|
||||
for (Standard_Integer anArgIter = 1; anArgIter < theArgNum; ++anArgIter)
|
||||
{
|
||||
Standard_CString anArg = theArgs[anArgIter];
|
||||
TCollection_AsciiString aFlag (anArg);
|
||||
aFlag.LowerCase();
|
||||
if (aFlag.IsRealValue (Standard_True) || aFlag.Search ("-") != 1)
|
||||
{
|
||||
aCmdArgs++;
|
||||
}
|
||||
}
|
||||
switch (aCmdArgs)
|
||||
{
|
||||
case 2 : aCmd = CloudForShape; break;
|
||||
case 7 : aCmd = CloudSphere; break;
|
||||
default :
|
||||
Message::SendFail ("Syntax error: wrong number of arguments! See usage:");
|
||||
theDI.PrintHelp (theArgs[0]);
|
||||
return 1;
|
||||
}
|
||||
TCollection_AsciiString aDistribution;
|
||||
gp_Pnt aDistCenter;
|
||||
Standard_Real aDistRadius = 0.0;
|
||||
Standard_Integer aDistNbPoints = 0;
|
||||
|
||||
// parse options
|
||||
Standard_Boolean toRandColors = Standard_False;
|
||||
Standard_Boolean hasNormals = Standard_True;
|
||||
Standard_Boolean isSetArgNorm = Standard_False;
|
||||
Standard_Boolean hasUV = Standard_False;
|
||||
bool toRandColors = false;
|
||||
bool hasNormals = true, hasUV = false;
|
||||
bool isDensityPoints = false;
|
||||
Standard_Real aDensity = 0.0, aDist = 0.0;
|
||||
Standard_Real aTol = Precision::Confusion();
|
||||
for (Standard_Integer anArgIter = 1; anArgIter < theArgNum; ++anArgIter)
|
||||
{
|
||||
Standard_CString anArg = theArgs[anArgIter];
|
||||
TCollection_AsciiString aFlag (anArg);
|
||||
TCollection_AsciiString aFlag (theArgs[anArgIter]);
|
||||
aFlag.LowerCase();
|
||||
if (aFlag == "-randcolors"
|
||||
|| aFlag == "-randcolor")
|
||||
{
|
||||
if (isSetArgNorm && hasNormals)
|
||||
{
|
||||
Message::SendFail ("Syntax error: normals can not be enabled with colors at the same time");
|
||||
return 1;
|
||||
}
|
||||
toRandColors = Standard_True;
|
||||
hasNormals = Standard_False;
|
||||
toRandColors = Draw::ParseOnOffIterator (theArgNum, theArgs, anArgIter);
|
||||
}
|
||||
else if (aFlag == "-normals"
|
||||
|| aFlag == "-normal")
|
||||
{
|
||||
if (toRandColors)
|
||||
{
|
||||
Message::SendFail ("Syntax error: normals can not be enabled with colors at the same time");
|
||||
return 1;
|
||||
}
|
||||
isSetArgNorm = Standard_True;
|
||||
hasNormals = Standard_True;
|
||||
hasNormals = Draw::ParseOnOffIterator (theArgNum, theArgs, anArgIter);
|
||||
}
|
||||
else if (aFlag == "-nonormals"
|
||||
|| aFlag == "-nonormal")
|
||||
{
|
||||
isSetArgNorm = Standard_True;
|
||||
hasNormals = Standard_False;
|
||||
hasNormals = !Draw::ParseOnOffIterator (theArgNum, theArgs, anArgIter);
|
||||
}
|
||||
else if (aFlag == "-uv"
|
||||
|| aFlag == "-texels")
|
||||
{
|
||||
hasUV = Standard_True;
|
||||
hasUV = Draw::ParseOnOffIterator (theArgNum, theArgs, anArgIter);
|
||||
}
|
||||
else if ((aFlag == "-dist"
|
||||
|| aFlag == "-distance")
|
||||
&& anArgIter + 1 < theArgNum
|
||||
&& Draw::ParseReal (theArgs[anArgIter + 1], aDist))
|
||||
{
|
||||
++anArgIter;
|
||||
if (aDist < 0.0)
|
||||
{
|
||||
theDI << "Syntax error: -distance value should be >= 0.0";
|
||||
return 1;
|
||||
}
|
||||
aDist = Max (aDist, Precision::Confusion());
|
||||
}
|
||||
else if ((aFlag == "-dens"
|
||||
|| aFlag == "-density")
|
||||
&& anArgIter + 1 < theArgNum
|
||||
&& Draw::ParseReal (theArgs[anArgIter + 1], aDensity))
|
||||
{
|
||||
++anArgIter;
|
||||
isDensityPoints = Standard_True;
|
||||
if (aDensity <= 0.0)
|
||||
{
|
||||
theDI << "Syntax error: -density value should be > 0.0";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if ((aFlag == "-tol"
|
||||
|| aFlag == "-tolerance")
|
||||
&& anArgIter + 1 < theArgNum
|
||||
&& Draw::ParseReal (theArgs[anArgIter + 1], aTol))
|
||||
{
|
||||
++anArgIter;
|
||||
if (aTol < Precision::Confusion())
|
||||
{
|
||||
theDI << "Syntax error: -tol value should be >= " << Precision::Confusion();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if ((aFlag == "-surface"
|
||||
|| aFlag == "-volume")
|
||||
&& anArgIter + 5 < theArgNum)
|
||||
{
|
||||
aDistribution = aFlag;
|
||||
aDistCenter.SetCoord (Draw::Atof (theArgs[anArgIter + 1]),
|
||||
Draw::Atof (theArgs[anArgIter + 2]),
|
||||
Draw::Atof (theArgs[anArgIter + 3]));
|
||||
aDistRadius = Draw::Atof (theArgs[anArgIter + 4]);
|
||||
aDistNbPoints = Draw::Atoi (theArgs[anArgIter + 5]);
|
||||
anArgIter += 5;
|
||||
}
|
||||
else if (aName.IsEmpty())
|
||||
{
|
||||
aName = theArgs[anArgIter];
|
||||
}
|
||||
else if (aShape.IsNull())
|
||||
{
|
||||
aShape = DBRep::Get (theArgs[anArgIter]);
|
||||
if (aShape.IsNull())
|
||||
{
|
||||
theDI << "Syntax error: invalid shape '" << theArgs[anArgIter] << "'";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
theDI << "Syntax error at '" << theArgs[anArgIter] << "'";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
Standard_CString aName = theArgs[1];
|
||||
Graphic3d_ArrayFlags aFlags = Graphic3d_ArrayFlags_None;
|
||||
if (hasNormals)
|
||||
{
|
||||
@@ -6350,125 +6388,80 @@ static Standard_Integer VPointCloud (Draw_Interpretor& theDI,
|
||||
|
||||
// generate arbitrary set of points
|
||||
Handle(Graphic3d_ArrayOfPoints) anArrayPoints;
|
||||
if (aCmd == CloudForShape)
|
||||
if (!aShape.IsNull())
|
||||
{
|
||||
Standard_CString aShapeName = theArgs[2];
|
||||
TopoDS_Shape aShape = DBRep::Get (aShapeName);
|
||||
|
||||
if (aShape.IsNull())
|
||||
class PointCloudPntFiller : public BRepLib_PointCloudShape
|
||||
{
|
||||
Message::SendFail() << "Error: no shape with name '" << aShapeName << "' found";
|
||||
return 1;
|
||||
}
|
||||
public:
|
||||
PointCloudPntFiller (Standard_Real theTol) : BRepLib_PointCloudShape (TopoDS_Shape(), theTol) {}
|
||||
void SetPointArray (const Handle(Graphic3d_ArrayOfPoints)& thePoints) { myPoints = thePoints; }
|
||||
|
||||
// calculate number of points
|
||||
TopLoc_Location aLocation;
|
||||
Standard_Integer aNbPoints = 0;
|
||||
for (TopExp_Explorer aFaceIt (aShape, TopAbs_FACE); aFaceIt.More(); aFaceIt.Next())
|
||||
{
|
||||
const TopoDS_Face& aFace = TopoDS::Face (aFaceIt.Current());
|
||||
Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation (aFace, aLocation);
|
||||
if (!aTriangulation.IsNull())
|
||||
protected:
|
||||
virtual void addPoint (const gp_Pnt& thePoint,
|
||||
const gp_Vec& theNorm,
|
||||
const gp_Pnt2d& theUV,
|
||||
const TopoDS_Shape& ) Standard_OVERRIDE
|
||||
{
|
||||
aNbPoints += aTriangulation->NbNodes();
|
||||
}
|
||||
}
|
||||
if (aNbPoints < 3)
|
||||
{
|
||||
Message::SendFail ("Error: shape should be triangulated");
|
||||
return 1;
|
||||
}
|
||||
|
||||
anArrayPoints = new Graphic3d_ArrayOfPoints (aNbPoints, aFlags);
|
||||
for (TopExp_Explorer aFaceIt (aShape, TopAbs_FACE); aFaceIt.More(); aFaceIt.Next())
|
||||
{
|
||||
const TopoDS_Face& aFace = TopoDS::Face (aFaceIt.Current());
|
||||
Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation (aFace, aLocation);
|
||||
if (aTriangulation.IsNull())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const gp_Trsf& aTrsf = aLocation.Transformation();
|
||||
|
||||
// extract normals from nodes
|
||||
TColgp_Array1OfDir aNormals (1, hasNormals ? aTriangulation->NbNodes() : 1);
|
||||
if (hasNormals)
|
||||
{
|
||||
Poly_Connect aPolyConnect (aTriangulation);
|
||||
StdPrs_ToolTriangulatedShape::Normal (aFace, aPolyConnect, aNormals);
|
||||
}
|
||||
|
||||
for (Standard_Integer aNodeIter = 1; aNodeIter <= aTriangulation->NbNodes(); ++aNodeIter)
|
||||
{
|
||||
gp_Pnt aPoint = aTriangulation->Node (aNodeIter);
|
||||
if (!aLocation.IsIdentity())
|
||||
const Standard_Integer aPntIndex = myPoints->AddVertex (thePoint, theUV);
|
||||
if (theNorm.SquareMagnitude() > gp::Resolution())
|
||||
{
|
||||
aPoint.Transform (aTrsf);
|
||||
if (hasNormals)
|
||||
{
|
||||
aNormals (aNodeIter).Transform (aTrsf);
|
||||
}
|
||||
myPoints->SetVertexNormal (aPntIndex, theNorm);
|
||||
}
|
||||
|
||||
// add vertex into array of points
|
||||
const Standard_Integer anIndexOfPoint = anArrayPoints->AddVertex (aPoint);
|
||||
if (toRandColors)
|
||||
if (myPoints->HasVertexColors())
|
||||
{
|
||||
Quantity_Color aColor (360.0 * Standard_Real(anIndexOfPoint) / Standard_Real(aNbPoints),
|
||||
Quantity_Color aColor (360.0 * Standard_Real(aPntIndex) / Standard_Real(myPoints->VertexNumberAllocated()),
|
||||
1.0, 0.5, Quantity_TOC_HLS);
|
||||
anArrayPoints->SetVertexColor (anIndexOfPoint, aColor);
|
||||
}
|
||||
|
||||
if (hasNormals)
|
||||
{
|
||||
anArrayPoints->SetVertexNormal (anIndexOfPoint, aNormals (aNodeIter));
|
||||
}
|
||||
if (hasUV
|
||||
&& aTriangulation->HasUVNodes())
|
||||
{
|
||||
anArrayPoints->SetVertexTexel (anIndexOfPoint, aTriangulation->UVNode (aNodeIter));
|
||||
myPoints->SetVertexColor (aPntIndex, aColor);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Handle(Graphic3d_ArrayOfPoints) myPoints;
|
||||
};
|
||||
|
||||
PointCloudPntFiller aPoitCloudTool (aTol);
|
||||
aPoitCloudTool.SetShape (aShape);
|
||||
aPoitCloudTool.SetDistance (aDist);
|
||||
|
||||
Standard_Integer aNbPoints = isDensityPoints
|
||||
? aPoitCloudTool.NbPointsByDensity (aDensity)
|
||||
: aPoitCloudTool.NbPointsByTriangulation();
|
||||
theDI << "Number of the generated points : " << aNbPoints << "\n";
|
||||
anArrayPoints = new Graphic3d_ArrayOfPoints (aNbPoints, aFlags);
|
||||
aPoitCloudTool.SetPointArray (anArrayPoints);
|
||||
Standard_Boolean isDone = isDensityPoints
|
||||
? aPoitCloudTool.GeneratePointsByDensity (aDensity)
|
||||
: aPoitCloudTool.GeneratePointsByTriangulation();
|
||||
if (!isDone)
|
||||
{
|
||||
Message::SendFail() << "Error: Point cloud was not generated";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (aCmd == CloudSphere)
|
||||
else if (!aDistribution.IsEmpty())
|
||||
{
|
||||
Standard_Real aCenterX = Draw::Atof (theArgs[2]);
|
||||
Standard_Real aCenterY = Draw::Atof (theArgs[3]);
|
||||
Standard_Real aCenterZ = Draw::Atof (theArgs[4]);
|
||||
Standard_Real aRadius = Draw::Atof (theArgs[5]);
|
||||
Standard_Integer aNbPoints = Draw::Atoi (theArgs[6]);
|
||||
const bool isSurface = aDistribution == "-surface";
|
||||
|
||||
TCollection_AsciiString aDistribution = TCollection_AsciiString(theArgs[7]);
|
||||
aDistribution.LowerCase();
|
||||
if ( aDistribution != "surface" && aDistribution != "volume" )
|
||||
anArrayPoints = new Graphic3d_ArrayOfPoints (aDistNbPoints, aFlags);
|
||||
std::mt19937 aRandomGenerator(0);
|
||||
std::uniform_real_distribution<> anAlphaDistrib(0.0, 2.0 * M_PI);
|
||||
std::uniform_real_distribution<> aBetaDistrib (0.0, 2.0 * M_PI);
|
||||
std::uniform_real_distribution<> aRadiusDistrib(0.0, aDistRadius);
|
||||
for (Standard_Integer aPntIt = 0; aPntIt < aDistNbPoints; ++aPntIt)
|
||||
{
|
||||
Message::SendFail ("Syntax error: wrong arguments. See usage:");
|
||||
theDI.PrintHelp (theArgs[0]);
|
||||
return 1;
|
||||
}
|
||||
Standard_Boolean isSurface = aDistribution == "surface";
|
||||
|
||||
gp_Pnt aCenter(aCenterX, aCenterY, aCenterZ);
|
||||
|
||||
anArrayPoints = new Graphic3d_ArrayOfPoints (aNbPoints, aFlags);
|
||||
for (Standard_Integer aPntIt = 0; aPntIt < aNbPoints; ++aPntIt)
|
||||
{
|
||||
Standard_Real anAlpha = (Standard_Real (rand() % 2000) / 1000.0) * M_PI;
|
||||
Standard_Real aBeta = (Standard_Real (rand() % 2000) / 1000.0) * M_PI;
|
||||
Standard_Real aDistance = isSurface ?
|
||||
aRadius : (Standard_Real (rand() % aNbPoints) / aNbPoints) * aRadius;
|
||||
Standard_Real anAlpha = anAlphaDistrib(aRandomGenerator);
|
||||
Standard_Real aBeta = aBetaDistrib (aRandomGenerator);
|
||||
Standard_Real aDistance = isSurface ? aDistRadius : aRadiusDistrib (aRandomGenerator);
|
||||
|
||||
gp_Dir aDir (Cos (anAlpha) * Sin (aBeta),
|
||||
Sin (anAlpha),
|
||||
Cos (anAlpha) * Cos (aBeta));
|
||||
gp_Pnt aPoint = aCenter.Translated (aDir.XYZ() * aDistance);
|
||||
gp_Pnt aPoint = aDistCenter.Translated (aDir.XYZ() * aDistance);
|
||||
|
||||
const Standard_Integer anIndexOfPoint = anArrayPoints->AddVertex (aPoint);
|
||||
if (toRandColors)
|
||||
{
|
||||
Quantity_Color aColor (360.0 * Standard_Real (anIndexOfPoint) / Standard_Real (aNbPoints),
|
||||
Quantity_Color aColor (360.0 * Standard_Real (anIndexOfPoint) / Standard_Real (aDistNbPoints),
|
||||
1.0, 0.5, Quantity_TOC_HLS);
|
||||
anArrayPoints->SetVertexColor (anIndexOfPoint, aColor);
|
||||
}
|
||||
@@ -6484,11 +6477,16 @@ static Standard_Integer VPointCloud (Draw_Interpretor& theDI,
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Message::SendFail ("Error: wrong number of arguments");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// set array of points in point cloud object
|
||||
Handle(AIS_PointCloud) aPointCloud = new AIS_PointCloud();
|
||||
aPointCloud->SetPoints (anArrayPoints);
|
||||
VDisplayAISObject (aName, aPointCloud);
|
||||
ViewerTest::Display (aName, aPointCloud);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -7149,18 +7147,23 @@ Prints the default vertex draw mode without -set parameter.
|
||||
)" /* [vvertexmode] */);
|
||||
|
||||
addCmd ("vpointcloud", VPointCloud, /* [vpointcloud] */ R"(
|
||||
vpointcloud name shape [-randColor] [-normals] [-noNormals] [-uv]
|
||||
vpointcloud name shape [-randColor {0|1}]=0 [-normals {0|1}]=1 [-uv {0|1}]=0
|
||||
[-distance Value]=0.0 [-density Value] [-tolerance Value]
|
||||
Create an interactive object for arbitrary set of points from triangulated shape.
|
||||
|
||||
vpointcloud name x y z r npts {surface|volume}
|
||||
... [-randColor] [-normals] [-noNormals] [-uv]
|
||||
vpointcloud name {-surface|-volume} x y z r npts
|
||||
[-randColor] [-normals] [-uv]
|
||||
Create arbitrary set of points (npts) randomly distributed
|
||||
on spheric surface or within spheric volume (x y z r).
|
||||
|
||||
Additional options:
|
||||
-randColor - generate random color per point
|
||||
-normals - generate normal per point (default)
|
||||
-noNormals - do not generate normal per point
|
||||
-normals generate or not normal per point
|
||||
-uv generate UV (texel) coordinates per point
|
||||
-randColor generate random color per point
|
||||
-distance distance from shape into the range [0, Value];
|
||||
-density density of points to generate randomly on surface;
|
||||
-tolerance cloud generator's tolerance; default value is Precision::Confusion();
|
||||
|
||||
)" /* [vpointcloud] */);
|
||||
|
||||
addCmd ("vpriority", VPriority, /* [vpriority] */ R"(
|
||||
|
@@ -19,6 +19,7 @@
|
||||
#include <Aspect_TypeOfMarker.hxx>
|
||||
#include <Bnd_Box.hxx>
|
||||
#include <BRep_Builder.hxx>
|
||||
#include <BRepLib_PointCloudShape.hxx>
|
||||
#include <DBRep.hxx>
|
||||
#include <DDocStd.hxx>
|
||||
#include <DDocStd_DrawDocument.hxx>
|
||||
@@ -45,10 +46,13 @@
|
||||
#include <Quantity_NameOfColor.hxx>
|
||||
#include <RWGltf_CafReader.hxx>
|
||||
#include <RWGltf_CafWriter.hxx>
|
||||
#include <RWMesh_FaceIterator.hxx>
|
||||
#include <RWStl.hxx>
|
||||
#include <RWObj.hxx>
|
||||
#include <RWObj_CafReader.hxx>
|
||||
#include <RWObj_CafWriter.hxx>
|
||||
#include <RWPly_CafWriter.hxx>
|
||||
#include <RWPly_PlyWriterContext.hxx>
|
||||
#include <SelectMgr_SelectionManager.hxx>
|
||||
#include <Standard_ErrorHandler.hxx>
|
||||
#include <StdSelect_ViewerSelector3d.hxx>
|
||||
@@ -62,6 +66,7 @@
|
||||
#include <TDataStd_Name.hxx>
|
||||
#include <TDocStd_Application.hxx>
|
||||
#include <TDocStd_Document.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
#include <UnitsAPI.hxx>
|
||||
@@ -75,6 +80,7 @@
|
||||
#include <VrmlData_ShapeConvert.hxx>
|
||||
#include <XCAFDoc_DocumentTool.hxx>
|
||||
#include <XCAFDoc_ShapeTool.hxx>
|
||||
#include <XCAFPrs_DocumentExplorer.hxx>
|
||||
#include <XSAlgo.hxx>
|
||||
#include <XSAlgo_AlgoContainer.hxx>
|
||||
#include <XSDRAW.hxx>
|
||||
@@ -2055,6 +2061,275 @@ static Standard_Integer meshinfo(Draw_Interpretor& di,
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : writeply
|
||||
//purpose : write PLY file
|
||||
//=======================================================================
|
||||
static Standard_Integer WritePly (Draw_Interpretor& theDI,
|
||||
Standard_Integer theNbArgs,
|
||||
const char** theArgVec)
|
||||
{
|
||||
Handle(TDocStd_Document) aDoc;
|
||||
Handle(TDocStd_Application) anApp = DDocStd::GetApplication();
|
||||
TCollection_AsciiString aShapeName, aFileName;
|
||||
|
||||
Standard_Real aDist = 0.0;
|
||||
Standard_Real aDens = Precision::Infinite();
|
||||
Standard_Real aTol = Precision::Confusion();
|
||||
bool hasColors = true, hasNormals = true, hasTexCoords = false, hasPartId = true, hasFaceId = false;
|
||||
bool isPntSet = false, isDensityPoints = false;
|
||||
TColStd_IndexedDataMapOfStringString aFileInfo;
|
||||
for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
|
||||
{
|
||||
TCollection_AsciiString anArg (theArgVec[anArgIter]);
|
||||
anArg.LowerCase();
|
||||
if (anArg == "-normal")
|
||||
{
|
||||
hasNormals = Draw::ParseOnOffIterator (theNbArgs, theArgVec, anArgIter);
|
||||
}
|
||||
else if (anArg == "-nonormal")
|
||||
{
|
||||
hasNormals = !Draw::ParseOnOffIterator (theNbArgs, theArgVec, anArgIter);
|
||||
}
|
||||
else if (anArg == "-color"
|
||||
|| anArg == "-nocolor"
|
||||
|| anArg == "-colors"
|
||||
|| anArg == "-nocolors")
|
||||
{
|
||||
hasColors = Draw::ParseOnOffNoIterator (theNbArgs, theArgVec, anArgIter);
|
||||
}
|
||||
else if (anArg == "-uv"
|
||||
|| anArg == "-nouv")
|
||||
{
|
||||
hasTexCoords = Draw::ParseOnOffNoIterator (theNbArgs, theArgVec, anArgIter);
|
||||
}
|
||||
else if (anArg == "-partid")
|
||||
{
|
||||
hasPartId = Draw::ParseOnOffNoIterator (theNbArgs, theArgVec, anArgIter);
|
||||
hasFaceId = hasFaceId && !hasPartId;
|
||||
}
|
||||
else if (anArg == "-surfid"
|
||||
|| anArg == "-surfaceid"
|
||||
|| anArg == "-faceid")
|
||||
{
|
||||
hasFaceId = Draw::ParseOnOffNoIterator (theNbArgs, theArgVec, anArgIter);
|
||||
hasPartId = hasPartId && !hasFaceId;
|
||||
}
|
||||
else if (anArg == "-pntset"
|
||||
|| anArg == "-pntcloud"
|
||||
|| anArg == "-pointset"
|
||||
|| anArg == "-pointcloud"
|
||||
|| anArg == "-cloud"
|
||||
|| anArg == "-points")
|
||||
{
|
||||
isPntSet = Draw::ParseOnOffIterator (theNbArgs, theArgVec, anArgIter);
|
||||
}
|
||||
else if ((anArg == "-dist"
|
||||
|| anArg == "-distance")
|
||||
&& anArgIter + 1 < theNbArgs
|
||||
&& Draw::ParseReal (theArgVec[anArgIter + 1], aDist))
|
||||
{
|
||||
++anArgIter;
|
||||
isPntSet = true;
|
||||
if (aDist < 0.0)
|
||||
{
|
||||
theDI << "Syntax error: -distance value should be >= 0.0";
|
||||
return 1;
|
||||
}
|
||||
aDist = Max (aDist, Precision::Confusion());
|
||||
}
|
||||
else if ((anArg == "-dens"
|
||||
|| anArg == "-density")
|
||||
&& anArgIter + 1 < theNbArgs
|
||||
&& Draw::ParseReal (theArgVec[anArgIter + 1], aDens))
|
||||
{
|
||||
++anArgIter;
|
||||
isDensityPoints = Standard_True;
|
||||
isPntSet = true;
|
||||
if (aDens <= 0.0)
|
||||
{
|
||||
theDI << "Syntax error: -density value should be > 0.0";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if ((anArg == "-tol"
|
||||
|| anArg == "-tolerance")
|
||||
&& anArgIter + 1 < theNbArgs
|
||||
&& Draw::ParseReal (theArgVec[anArgIter + 1], aTol))
|
||||
{
|
||||
++anArgIter;
|
||||
isPntSet = true;
|
||||
if (aTol < Precision::Confusion())
|
||||
{
|
||||
theDI << "Syntax error: -tol value should be >= " << Precision::Confusion();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (anArg == "-comments"
|
||||
&& anArgIter + 1 < theNbArgs)
|
||||
{
|
||||
aFileInfo.Add ("Comments", theArgVec[++anArgIter]);
|
||||
}
|
||||
else if (anArg == "-author"
|
||||
&& anArgIter + 1 < theNbArgs)
|
||||
{
|
||||
aFileInfo.Add ("Author", theArgVec[++anArgIter]);
|
||||
}
|
||||
else if (aDoc.IsNull())
|
||||
{
|
||||
if (aShapeName.IsEmpty())
|
||||
{
|
||||
aShapeName = theArgVec[anArgIter];
|
||||
}
|
||||
|
||||
Standard_CString aNameVar = theArgVec[anArgIter];
|
||||
DDocStd::GetDocument (aNameVar, aDoc, false);
|
||||
if (aDoc.IsNull())
|
||||
{
|
||||
TopoDS_Shape aShape = DBRep::Get (aNameVar);
|
||||
if (!aShape.IsNull())
|
||||
{
|
||||
anApp->NewDocument (TCollection_ExtendedString ("BinXCAF"), aDoc);
|
||||
Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool (aDoc->Main());
|
||||
aShapeTool->AddShape (aShape);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (aFileName.IsEmpty())
|
||||
{
|
||||
aFileName = theArgVec[anArgIter];
|
||||
}
|
||||
else
|
||||
{
|
||||
theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (aDoc.IsNull()
|
||||
&& !aShapeName.IsEmpty())
|
||||
{
|
||||
theDI << "Syntax error: '" << aShapeName << "' is not a shape nor document";
|
||||
return 1;
|
||||
}
|
||||
else if (aDoc.IsNull()
|
||||
|| aFileName.IsEmpty())
|
||||
{
|
||||
theDI << "Syntax error: wrong number of arguments";
|
||||
return 1;
|
||||
}
|
||||
|
||||
TDF_LabelSequence aRootLabels;
|
||||
Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool (aDoc->Main());
|
||||
aShapeTool->GetFreeShapes (aRootLabels);
|
||||
if (aRootLabels.IsEmpty())
|
||||
{
|
||||
theDI << "Error: empty document";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (isPntSet)
|
||||
{
|
||||
class PointCloudPlyWriter : public BRepLib_PointCloudShape, public RWPly_PlyWriterContext
|
||||
{
|
||||
public:
|
||||
PointCloudPlyWriter (Standard_Real theTol)
|
||||
: BRepLib_PointCloudShape (TopoDS_Shape(), theTol) {}
|
||||
|
||||
void AddFaceColor (const TopoDS_Shape& theFace, const Graphic3d_Vec4ub& theColor)
|
||||
{ myFaceColor.Bind (theFace, theColor); }
|
||||
|
||||
protected:
|
||||
virtual void addPoint (const gp_Pnt& thePoint,
|
||||
const gp_Vec& theNorm,
|
||||
const gp_Pnt2d& theUV,
|
||||
const TopoDS_Shape& theFace)
|
||||
{
|
||||
Graphic3d_Vec4ub aColor;
|
||||
myFaceColor.Find (theFace, aColor);
|
||||
RWPly_PlyWriterContext::WriteVertex (thePoint,
|
||||
Graphic3d_Vec3 ((float )theNorm.X(), (float )theNorm.Y(), (float )theNorm.Z()),
|
||||
Graphic3d_Vec2 ((float )theUV.X(), (float )theUV.Y()),
|
||||
aColor);
|
||||
}
|
||||
|
||||
private:
|
||||
NCollection_DataMap<TopoDS_Shape, Graphic3d_Vec4ub> myFaceColor;
|
||||
};
|
||||
|
||||
PointCloudPlyWriter aPlyCtx (aTol);
|
||||
aPlyCtx.SetNormals (hasNormals);
|
||||
aPlyCtx.SetColors (hasColors);
|
||||
aPlyCtx.SetTexCoords (hasTexCoords);
|
||||
|
||||
TopoDS_Compound aComp;
|
||||
BRep_Builder().MakeCompound (aComp);
|
||||
for (XCAFPrs_DocumentExplorer aDocExplorer (aDoc, aRootLabels, XCAFPrs_DocumentExplorerFlags_OnlyLeafNodes);
|
||||
aDocExplorer.More(); aDocExplorer.Next())
|
||||
{
|
||||
const XCAFPrs_DocumentNode& aDocNode = aDocExplorer.Current();
|
||||
for (RWMesh_FaceIterator aFaceIter (aDocNode.RefLabel, aDocNode.Location, true, aDocNode.Style); aFaceIter.More(); aFaceIter.Next())
|
||||
{
|
||||
BRep_Builder().Add (aComp, aFaceIter.Face());
|
||||
Graphic3d_Vec4ub aColorVec (255);
|
||||
if (aFaceIter.HasFaceColor())
|
||||
{
|
||||
Graphic3d_Vec4 aColorF = aFaceIter.FaceColor();
|
||||
aColorVec.SetValues ((unsigned char )int(aColorF.r() * 255.0f),
|
||||
(unsigned char )int(aColorF.g() * 255.0f),
|
||||
(unsigned char )int(aColorF.b() * 255.0f),
|
||||
(unsigned char )int(aColorF.a() * 255.0f));
|
||||
}
|
||||
aPlyCtx.AddFaceColor (aFaceIter.Face(), aColorVec);
|
||||
}
|
||||
}
|
||||
aPlyCtx.SetShape (aComp);
|
||||
|
||||
Standard_Integer aNbPoints = isDensityPoints
|
||||
? aPlyCtx.NbPointsByDensity (aDens)
|
||||
: aPlyCtx.NbPointsByTriangulation();
|
||||
if (aNbPoints <= 0)
|
||||
{
|
||||
theDI << "Error: unable to generate points";
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!aPlyCtx.Open (aFileName)
|
||||
|| !aPlyCtx.WriteHeader (aNbPoints, 0, TColStd_IndexedDataMapOfStringString()))
|
||||
{
|
||||
theDI << "Error: unable to create file '" << aFileName << "'";
|
||||
return 0;
|
||||
}
|
||||
|
||||
Standard_Boolean isDone = isDensityPoints
|
||||
? aPlyCtx.GeneratePointsByDensity (aDens)
|
||||
: aPlyCtx.GeneratePointsByTriangulation();
|
||||
if (!isDone)
|
||||
{
|
||||
theDI << "Error: Point cloud was not generated in file '" << aFileName << "'";
|
||||
}
|
||||
else if (!aPlyCtx.Close())
|
||||
{
|
||||
theDI << "Error: Point cloud file '" << aFileName << "' was not written";
|
||||
}
|
||||
else
|
||||
{
|
||||
theDI << aNbPoints;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Handle(Draw_ProgressIndicator) aProgress = new Draw_ProgressIndicator (theDI, 1);
|
||||
RWPly_CafWriter aPlyCtx (aFileName);
|
||||
aPlyCtx.SetNormals (hasNormals);
|
||||
aPlyCtx.SetColors (hasColors);
|
||||
aPlyCtx.SetTexCoords (hasTexCoords);
|
||||
aPlyCtx.SetPartId (hasPartId);
|
||||
aPlyCtx.SetFaceId (hasFaceId);
|
||||
aPlyCtx.Perform (aDoc, aFileInfo, aProgress->Start());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void XSDRAWSTLVRML::InitCommands (Draw_Interpretor& theCommands)
|
||||
@@ -2160,6 +2435,25 @@ void XSDRAWSTLVRML::InitCommands (Draw_Interpretor& theCommands)
|
||||
theCommands.Add ("meshdeform", "display deformed mesh", __FILE__, meshdeform, g );
|
||||
theCommands.Add ("mesh_edge_width", "set width of edges", __FILE__, mesh_edge_width, g );
|
||||
theCommands.Add ("meshinfo", "displays the number of nodes and triangles", __FILE__, meshinfo, g );
|
||||
theCommands.Add ("WritePly", R"(
|
||||
WritePly Doc file [-normals {0|1}]=1 [-colors {0|1}]=1 [-uv {0|1}]=0 [-partId {0|1}]=1 [-faceId {0|1}]=0
|
||||
[-pointCloud {0|1}]=0 [-distance Value]=0.0 [-density Value] [-tolerance Value]
|
||||
Write document or triangulated shape into PLY file.
|
||||
-normals write per-vertex normals
|
||||
-colors write per-vertex colors
|
||||
-uv write per-vertex UV coordinates
|
||||
-partId write per-element part index (alternative to -faceId)
|
||||
-faceId write per-element face index (alternative to -partId)
|
||||
|
||||
Generate point cloud out of the shape and write it into PLY file.
|
||||
-pointCloud write point cloud instead without triangulation indices
|
||||
-distance sets distance from shape into the range [0, Value];
|
||||
-density sets density of points to generate randomly on surface;
|
||||
-tolerance sets tolerance; default value is Precision::Confusion();
|
||||
)", __FILE__, WritePly, g);
|
||||
theCommands.Add ("writeply",
|
||||
"writeply shape file",
|
||||
__FILE__, WritePly, g);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
@@ -5,3 +5,4 @@
|
||||
005 gltf_lateload
|
||||
006 obj_read
|
||||
007 obj_write
|
||||
008 ply_write
|
||||
|
14
tests/de_mesh/ply_write/equerre
Normal file
14
tests/de_mesh/ply_write/equerre
Normal file
@@ -0,0 +1,14 @@
|
||||
puts "============"
|
||||
puts "0029325: Modeling Algorithms - add tool BRepLib_PointCloudShape for generation point cloud for specified shape"
|
||||
puts "============"
|
||||
puts ""
|
||||
|
||||
pload XDE OCAF MODELING VISUALIZATION
|
||||
|
||||
set aNbPntsExpected 32581
|
||||
set aTmpPly ${imagedir}/${casename}_tmp.ply
|
||||
lappend occ_tmp_files $aTmpPly
|
||||
|
||||
restore [locate_data_file bug29325_EQUERRE.brep] aShape
|
||||
set aNbPnts [writeply aShape $aTmpPly -pointCloud -dist 0.0 -dens 0.1 -colors 0]
|
||||
if {$aNbPnts != $aNbPntsExpected} { puts "Error: ($aNbPnts) generated while expected ($aNbPntsExpected)" }
|
14
tests/de_mesh/ply_write/sangle
Normal file
14
tests/de_mesh/ply_write/sangle
Normal file
@@ -0,0 +1,14 @@
|
||||
puts "============"
|
||||
puts "0029325: Modeling Algorithms - add tool BRepLib_PointCloudShape for generation point cloud for specified shape"
|
||||
puts "============"
|
||||
puts ""
|
||||
|
||||
pload XDE OCAF MODELING VISUALIZATION
|
||||
|
||||
set aNbPntsExpected 27890
|
||||
set aTmpPly ${imagedir}/${casename}_tmp.ply
|
||||
lappend occ_tmp_files $aTmpPly
|
||||
|
||||
restore [locate_data_file bug29325_SANGLE_DE_FIXATION.brep] aShape
|
||||
set aNbPnts [writeply aShape $aTmpPly -pointCloud -dist 0.0 -dens 0.5 -colors 0]
|
||||
if {$aNbPnts != $aNbPntsExpected} { puts "Error: ($aNbPnts) generated while expected ($aNbPntsExpected)" }
|
@@ -21,7 +21,7 @@ vrotate 0.2 0.0 0.0
|
||||
vdump $::imagedir/${::casename}_green.png
|
||||
|
||||
# random colors mode
|
||||
vpointcloud p s -randcolors
|
||||
vpointcloud p s -randcolors -nonormals
|
||||
vdump $::imagedir/${::casename}_rand.png
|
||||
|
||||
# texture mapping
|
||||
|
Reference in New Issue
Block a user