1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-09 13:22:24 +03:00

0029325: Modeling Algorithms - add tool BRepLib_PointCloudShape for generation point cloud for specified shape

Added PLY writing tools RWPly_CafWriter and RWPly_PlyWriterContext.

Added tool BRepLib_PointCloudShape generating point cloud from shape in two ways:
- random points on surface with specified density;
- points from triangulation nodes.

StdPrs_ToolTriangulatedShape::ComputeNormals() has been moved to
BRepLib_ToolTriangulatedShape for reusing outside of AIS.

Command vpointcloud has been extended to use new generation tool.
Command writeply has been added to write triangulation or point set into PLY format.
This commit is contained in:
gka
2017-11-08 17:13:53 +03:00
committed by smoskvin
parent ae38730d35
commit e2d60d0f7f
20 changed files with 2017 additions and 258 deletions

View File

@@ -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);
}
//==============================================================================