hyporo-cpp/source/hpr/csg/shape.hpp
2023-04-10 22:01:56 +05:00

366 lines
8.0 KiB
C++

#pragma once
#include <hpr/containers/array.hpp>
#include <hpr/math/scalar.hpp>
#include <hpr/math/vector.hpp>
#include <map>
#include <string>
#include <Geom_Surface.hxx>
#include <GeomLProp_SLProps.hxx>
#include <Poly_Triangle.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Vertex.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Wire.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Compound.hxx>
#include <TopoDS_CompSolid.hxx>
#include <TopoDS_Shell.hxx>
#include <TopoDS_Solid.hxx>
#include <TopExp_Explorer.hxx>
#include <BRepBuilderAPI_MakeVertex.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRepBuilderAPI_MakeShell.hxx>
#include <BRepBuilderAPI_MakeSolid.hxx>
#include <BRepBuilderAPI_Sewing.hxx>
#include <BRep_Builder.hxx>
#include <BRepBndLib.hxx>
#include <BRep_Tool.hxx>
#include <BRepTools.hxx>
#include <BRepGProp.hxx>
#include <GProp_GProps.hxx>
#include <ShapeUpgrade_UnifySameDomain.hxx>
#include <BRepExtrema_DistShapeShape.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <BRepBuilderAPI_GTransform.hxx>
#include <BRepFilletAPI_MakeFillet.hxx>
#include <BRepAlgoAPI_Fuse.hxx>
#include <BRepAlgoAPI_Common.hxx>
#include <BRepAlgoAPI_Cut.hxx>
#include <BRepPrimAPI_MakeSphere.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
#include <BRepPrimAPI_MakePrism.hxx>
#include <STEPControl_Writer.hxx>
#include <Interface_Static.hxx>
#include <BRepMesh_IncrementalMesh.hxx>
#include <Poly_PolygonOnTriangulation.hxx>
#include <Poly_Triangulation.hxx>
#include <TopAbs_ShapeEnum.hxx>
#include <TopLoc_Location.hxx>
#include <NCollection_List.hxx>
#include <ShapeFix_Solid.hxx>
#include <ShapeFix_Shell.hxx>
#include <ShapeFix_Face.hxx>
namespace hpr::csg
{
class Shape;
}
namespace std
{
template<>
struct less<hpr::csg::Shape>
{
bool operator() (const hpr::csg::Shape& s1, const hpr::csg::Shape& s2) const;
};
}
namespace hpr::csg
{
// Class declaration
class Shape
{
public:
enum class Type
{
Compound,
Compsolid,
Solid,
Shell,
Face,
Wire,
Edge,
Vertex,
Shape,
Unknown
};
enum class Format
{
Unknown,
STEP
};
class Metadata
{
public:
std::string label;
public:
Metadata() :
label {"default"}
{}
void merge(const Metadata& data)
{
if (label == "default" && data.label != "default")
label = data.label;
}
};
public:
// TODO: clean up map
static
std::map<Shape, Shape::Metadata> metadata;
protected:
TopoDS_Shape p_shape;
public:
[[nodiscard]]
TopoDS_Shape tshape() const { return p_shape; }
Shape(const TopoDS_Shape& s) :
p_shape {s}
{}
Shape(TopoDS_Shape&& s) noexcept:
p_shape {std::forward<TopoDS_Shape>(s)}
{}
public:
Shape() :
p_shape {}
{}
virtual
~Shape() = default;
//{
//if (metadata.contains(*this))
// metadata.erase(*this);
//}
[[nodiscard]]
Type type() const
{
switch (p_shape.ShapeType())
{
case TopAbs_VERTEX:
return Type::Vertex;
case TopAbs_EDGE:
return Type::Edge;
case TopAbs_FACE:
return Type::Face;
case TopAbs_WIRE:
return Type::Wire;
case TopAbs_SHELL:
return Type::Shell;
case TopAbs_SOLID:
return Type::Solid;
case TopAbs_COMPOUND:
return Type::Compound;
case TopAbs_COMPSOLID:
return Type::Compsolid;
case TopAbs_SHAPE:
return Type::Shape;
default:
return Type::Unknown;
}
}
[[nodiscard]]
vec3 center() const
{
GProp_GProps props;
switch (type())
{
case Type::Solid:
case Type::Compsolid:
case Type::Compound:
BRepGProp::VolumeProperties(p_shape, props);
case Type::Shell:
case Type::Face:
BRepGProp::SurfaceProperties(p_shape, props);
default:
BRepGProp::LinearProperties(p_shape, props);
}
gp_Pnt center {props.CentreOfMass()};
return vec3 {static_cast<scalar>(center.X()), static_cast<scalar>(center.Y()), static_cast<scalar>(center.Z())};
}
[[nodiscard]]
double length() const
{
GProp_GProps props;
switch (type())
{
case Type::Vertex:
return 0;
default:
BRepGProp::LinearProperties(p_shape, props);
return props.Mass();
}
}
[[nodiscard]]
double area() const
{
GProp_GProps props;
switch (type())
{
case Type::Vertex:
case Type::Edge:
case Type::Wire:
return 0;
default:
BRepGProp::SurfaceProperties(p_shape, props);
return props.Mass();
}
}
[[nodiscard]]
double volume() const
{
GProp_GProps props;
switch (type())
{
case Type::Compsolid:
case Type::Solid:
BRepGProp::VolumeProperties(p_shape, props);
return props.Mass();
default:
return 0;
}
}
void label(const std::string& label) const
{
metadata[*this].label = label;
}
[[nodiscard]]
std::string label() const
{
return metadata[*this].label;
}
void dump(const std::string& filename, Format format) const
{
if (p_shape.IsNull())
throw std::runtime_error("Trying to export null shape");
switch (format)
{
case Format::STEP:
{
STEPControl_Writer writer;
Interface_Static::SetCVal("xstep.cascade.unit", "MM");
Interface_Static::SetCVal("write.step.unit", "MM");
Interface_Static::SetIVal("write.step.nonmanifold", 1);
writer.Transfer(p_shape, STEPControl_AsIs);
writer.Write(filename.c_str());
break;
}
case Format::Unknown:
default:
throw std::invalid_argument("Unknown export format");
}
}
//
[[nodiscard]]
sarray<vec3, 2> boundingBox() const
{
Bnd_Box bbox;
BRepBndLib::Add(p_shape, bbox, true);
gp_Pnt p1 {bbox.CornerMin()};
gp_Pnt p2 {bbox.CornerMax()};
return sarray<vec3, 2> {
{static_cast<scalar>(p1.X()), static_cast<scalar>(p1.Y()), static_cast<scalar>(p1.Z())},
{static_cast<scalar>(p2.X()), static_cast<scalar>(p2.Y()), static_cast<scalar>(p2.Z())}
};
}
void incrementalMesh(double deflection)
{
BRepTools::Clean(p_shape);
BRepMesh_IncrementalMesh(p_shape, deflection, true);
}
darray<Shape> subShapes(Type type) const
{
darray<Shape> shapes;
for (TopExp_Explorer exp(p_shape, static_cast<TopAbs_ShapeEnum>(type)); exp.More(); exp.Next())
shapes.push(Shape(exp.Current()));
return shapes;
}
darray<Shape> edges() const
{
return subShapes(Type::Edge);
}
darray<Shape> faces() const
{
return subShapes(Type::Face);
}
darray<Shape> shells() const
{
return subShapes(Type::Shell);
}
};
double distance(const Shape& lhs, const Shape& rhs)
{
return BRepExtrema_DistShapeShape(lhs.tshape(), rhs.tshape()).Value();
}
}