Commit 434bb32f authored by Dennis Gläser's avatar Dennis Gläser
Browse files

Merge branch 'feature/python-compute-area-length-volume' into 'master'

Feature/python compute area length volume

See merge request tools/frackit!158
parents d695aa3a 9d81b9db
......@@ -34,6 +34,7 @@
#include <TopoDS_Face.hxx>
#include <TopoDS_Shell.hxx>
#include <TopoDS_Solid.hxx>
#include <TopoDS_Compound.hxx>
#include <Standard.hxx>
#include <frackit/geometry/geometry.hh>
......@@ -112,6 +113,15 @@ struct DimensionalityTraits<TopoDS_Solid>
: public DimensionalityTraits<TopoDS_Shape>
{ static constexpr int geometryDimension() { return 3; } };
/*!
* \brief Specialization for Brep solids.
* \note For compounds the geometry dimension is also not clear.
*/
template<>
struct DimensionalityTraits<TopoDS_Compound>
: public DimensionalityTraits<TopoDS_Shape>
{};
/*!
* \brief The dimension of the abstract base class is not known.
* Thus, we provoke compiler errors when this is uses.
......
......@@ -115,7 +115,7 @@ public:
//! Return the radius of the cylinder
ctype radius() const { return bottom_.radius(); }
//! Return the area of this surface
ctype area() { return 2.0*M_PI*radius()*height(); }
ctype area() const { return 2.0*M_PI*radius()*height(); }
//! Return the circle describing the top boundary of this surface
const Circle& upperBoundingCircle() const { return top_; }
......
......@@ -26,12 +26,15 @@
#define FRACKIT_MAGNITUDE_AREA_HH
#include <cmath>
#include <numeric>
#include <gp_Pnt.hxx>
#include <TopoDS_Face.hxx>
#include <BRepGProp.hxx>
#include <GProp_GProps.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Shell.hxx>
#include <frackit/occ/breputilities.hh>
#include <frackit/precision/precision.hh>
namespace Frackit {
......@@ -64,6 +67,26 @@ ctype computeArea(const TopoDS_Face& face,
return gprops.Mass();
}
/*!
* \ingroup Magnitude
* \brief Returns the area of a TopoDS_Shell.
* \param shell The shell
* \param eps Tolerance value to be used
* \param loc A location; defaults to the origin, however,
* higher precision is achieved if a point close
* to the actual face is chosen.
*/
template<class ctype = double>
ctype computeArea(const TopoDS_Shell& shell,
ctype eps = Precision<ctype>::confusion(),
const gp_Pnt& loc = gp_Pnt())
{
const auto faces = OCCUtilities::getFaces(shell);
auto addArea = [&] (const ctype& cur, const TopoDS_Face& face)
{ return cur + computeArea(face, eps, loc); };
return std::accumulate(faces.begin(), faces.end(), ctype(0.0), addArea);
}
} // end namespace Frackit
#endif // FRACKIT_MAGNITUDE_AREA_HH
......@@ -26,15 +26,18 @@
#define FRACKIT_MAGNITUDE_LENGTH_HH
#include <cmath>
#include <numeric>
#include <Standard_Handle.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Wire.hxx>
#include <Geom_Curve.hxx>
#include <GeomAdaptor_Curve.hxx>
#include <GCPnts_AbscissaPoint.hxx>
#include <frackit/occ/geomutilities.hh>
#include <frackit/occ/breputilities.hh>
#include <frackit/geometry/circle.hh>
#include <frackit/geometry/ellipse.hh>
......@@ -73,6 +76,19 @@ template<class ctype = double>
ctype computeLength(const TopoDS_Edge& edge)
{ return computeLength(OCCUtilities::getGeomHandle(edge)); }
/*!
* \ingroup Magnitude
* \brief Returns the length of a BRep wire.
*/
template<class ctype = double>
ctype computeLength(const TopoDS_Wire& wire)
{
const auto edges = OCCUtilities::getEdges(wire);
auto addLength = [] (const ctype& cur, const TopoDS_Edge& edge)
{ return cur + computeLength(edge); };
return std::accumulate(edges.begin(), edges.end(), ctype(0.0), addLength);
}
/*!
* \ingroup Magnitude
* \brief Returns the length of a circle (circumference).
......
......@@ -29,9 +29,12 @@
#include <gp_Pnt.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Shell.hxx>
#include <TopoDS_Wire.hxx>
#include <TopoDS_Edge.hxx>
#include <frackit/precision/precision.hh>
#include "length.hh"
#include "area.hh"
#include "volume.hh"
......@@ -78,6 +81,14 @@ template<class ctype = double>
ctype computeMagnitude(const TopoDS_Edge& edge)
{ return computeLength(edge); }
/*!
* \ingroup Magnitude
* \brief Returns the length of a BRep wire
*/
template<class ctype = double>
ctype computeMagnitude(const TopoDS_Wire& wire)
{ return computeLength(wire); }
/*!
* \ingroup Magnitude
* \brief Returns the area of a BRep face
......@@ -93,6 +104,21 @@ ctype computeMagnitude(const TopoDS_Face& face,
const gp_Pnt& loc = gp_Pnt())
{ return computeArea(face, eps, loc); }
/*!
* \ingroup Magnitude
* \brief Returns the area of a BRep shell
* \param shell The shell
* \param eps Tolerance value to be used
* \param loc A location; defaults to the origin, however,
* higher precision is achieved if a point close
* to the actual face is chosen.
*/
template<class ctype = double>
ctype computeMagnitude(const TopoDS_Shell& shell,
ctype eps = Precision<ctype>::confusion(),
const gp_Pnt& loc = gp_Pnt())
{ return computeArea(shell, eps, loc); }
/*!
* \ingroup Magnitude
* \brief Returns the volume of a BRep solid
......
......@@ -36,6 +36,15 @@
namespace Frackit {
/*!
* \ingroup Magnitude
* \brief Returns the volume of an internal geometry
* that has a volume() function available.
*/
template<class Geometry>
typename Geometry::ctype computeVolume(const Geometry& geometry)
{ return geometry.volume(); }
/*!
* \ingroup Magnitude
* \brief Returns the volume of a TopoDS_Solid.
......
add_subdirectory(common)
add_subdirectory(geometry)
add_subdirectory(geometryutilities)
add_subdirectory(io)
add_subdirectory(occutilities)
add_subdirectory(precision)
......
......@@ -15,7 +15,9 @@ ellipticalgeometry.hh
emptyintersection.hh
geometry.hh
hollowcylinder.hh
intersect.hh
line.hh
magnitude.hh
plane.hh
point.hh
polygon.hh
......
......@@ -23,6 +23,8 @@
#include <pybind11/pybind11.h>
#include <TopoDS_Shape.hxx>
#include "registerdimensionproperties.hh"
#include "brepwrapper.hh"
namespace Frackit::Python {
......@@ -36,6 +38,7 @@ namespace Detail {
using Wrapper = BRepWrapper<Shape>;
pybind11::class_<Wrapper> cls(module, className.c_str());
cls.def("name", &Wrapper::name, "return the name of the wrapper");
registerDimensionProperties(cls);
// add constructor from other shape wrappers
if constexpr(std::is_same_v<Shape, TopoDS_Shape>)
......@@ -57,6 +60,7 @@ namespace Detail {
using Wrapper = CompoundWrapper;
pybind11::class_<Wrapper> cls(module, "OCCCompoundWrapper");
cls.def(pybind11::init<>());
registerDimensionProperties(cls);
// functions to add shapes to the compound
cls.def("name", &Wrapper::name, "return the name of the wrapper");
......
......@@ -25,9 +25,18 @@
// supported (registered) geometry types (so far)
#include <frackit/geometry/disk.hh>
#include <frackit/geometry/segment.hh>
#include <frackit/geometry/vector.hh>
#include <frackit/geometry/circle.hh>
#include <frackit/geometry/ellipse.hh>
#include <frackit/geometry/ellipsearc.hh>
#include <frackit/geometry/triangle.hh>
#include <frackit/geometry/quadrilateral.hh>
#include <frackit/geometry/polygon.hh>
#include <frackit/geometry/box.hh>
#include <frackit/geometry/sphere.hh>
#include <frackit/geometry/cylinder.hh>
#include <frackit/geometry/hollowcylinder.hh>
#include <frackit/geometry/cylindersurface.hh>
#include <frackit/python/geometry/brepwrapper.hh>
#include <frackit/python/common/extractctype.hh>
......@@ -74,11 +83,24 @@ template<class ctype>
void registerMagnitude(py::module& module)
{
using namespace Frackit;
Detail::registerMagnitude< Vector<ctype, 3> >(module);
Detail::registerMagnitude< Segment<ctype, 3> >(module);
Detail::registerMagnitude< Circle<ctype, 3> >(module);
Detail::registerMagnitude< Ellipse<ctype, 3> >(module);
Detail::registerMagnitude< EllipseArc<ctype, 3> >(module);
Detail::registerMagnitude< Disk<ctype> >(module);
Detail::registerMagnitude< Triangle<ctype, 3> >(module);
Detail::registerMagnitude< Quadrilateral<ctype, 3> >(module);
Detail::registerMagnitude< Polygon<ctype, 3> >(module);
Detail::registerMagnitude< CylinderSurface<ctype> >(module);
Detail::registerMagnitude< Cylinder<ctype> >(module);
Detail::registerMagnitude< HollowCylinder<ctype> >(module);
Detail::registerMagnitude< Box<ctype> >(module);
Detail::registerMagnitude< Sphere<ctype> >(module);
Detail::registerMagnitude< EdgeWrapper >(module);
Detail::registerMagnitude< WireWrapper >(module);
Detail::registerMagnitude< FaceWrapper >(module);
Detail::registerMagnitude< ShellWrapper >(module);
Detail::registerMagnitude< SolidWrapper >(module);
}
......
......@@ -20,6 +20,7 @@
#define FRACKIT_PYTHON_GEOMETRY_REGISTER_DIMENSION_PROPERTIES_HH
#include <pybind11/pybind11.h>
#include <frackit/python/geometryutilities/dimension.hh>
namespace Frackit::Python {
......@@ -28,8 +29,16 @@ namespace py = pybind11;
template<class Geometry, class... options>
void registerDimensionProperties(py::class_<Geometry, options...>& cls)
{
cls.def_property_readonly_static("myDimension", [] (py::object /*self*/) { return Geometry::myDimension(); }, "dimension of the geometry");
cls.def_property_readonly_static("worldDimension", [] (py::object /*self*/) { return Geometry::worldDimension(); }, "space dimension");
if constexpr (HasFixedDimensionality<Geometry>::value)
cls.def_property_readonly_static("myDimension",
[] (py::object /*self*/)
{ return DimensionalityTraits<Geometry>::geometryDimension(); },
"dimension of the geometry");
cls.def_property_readonly_static("worldDimension",
[] (py::object /*self*/)
{ return DimensionalityTraits<Geometry>::worldDimension(); },
"space dimension");
}
} // end namespace Frackit::Python
......
install(FILES
dimension.hh
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/frackit/python/geometryutilities)
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*****************************************************************************
* See the file COPYING for full copying permissions. *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*****************************************************************************/
#ifndef FRACKIT_PYTHON_GEOMETRY_DIMENSION_HH
#define FRACKIT_PYTHON_GEOMETRY_DIMENSION_HH
#include <type_traits>
#include <TopoDS_Shape.hxx>
#include <TopoDS_Compound.hxx>
#include <frackit/common/extractdimension.hh>
#include <frackit/python/geometry/brepwrapper.hh>
namespace Frackit::Python {
//! import traits from Frackit namespace
template<class Geometry>
struct DimensionalityTraits
: public Frackit::DimensionalityTraits<Geometry>
{};
//! dimensionality traits for brep shape wrappers
template<class Shape>
struct DimensionalityTraits<BRepWrapper<Shape>>
: public Frackit::DimensionalityTraits<Shape>
{};
//! Helper struct to check if a geometry has dimensionality known at compile-time
template<class Geometry>
struct HasFixedDimensionality : public std::true_type {};
template<>
struct HasFixedDimensionality<TopoDS_Shape> : public std::false_type {};
template<>
struct HasFixedDimensionality<TopoDS_Compound> : public std::false_type {};
template<class Shape>
struct HasFixedDimensionality<BRepWrapper<Shape>>
: public HasFixedDimensionality<Shape> {};
} // end namespace Frackit::Python
#endif
......@@ -93,6 +93,49 @@ def Circle(*args, **kwargs):
elif dim == 2: raiseGeometryConstructorException("circle", "notImplemented") # todo
else: return Circle_3(*args, **kwargs)
###################################################
# Compute the length of a one-dimensional geometry
def computeLength(geo):
"""
Compute the length of a one-dimensional finite geometry.
"""
try: geoDim = geo.myDimension
except: raise TypeError("The given geometry does not state its dimensionality. "\
"Try using computeMagnitude() instead.")
if geoDim != 1:
raise TypeError("Length can only be computed for one-dimensional geometries")
return _geometry.computeMagnitude(geo)
# Compute the area of a two-dimensional geometry
def computeArea(geo):
"""
Compute the area of a two-dimensional finite geometry.
"""
try: geoDim = geo.myDimension
except: raise TypeError("The given geometry does not state its dimensionality. "\
"Try using computeMagnitude() instead.")
if geoDim != 2:
raise TypeError("Area can only be computed for two-dimensional geometries")
return _geometry.computeMagnitude(geo)
# Compute the volume of a three-dimensional geometry
def computeVolume(geo):
"""
Compute the volume of a three-dimensional finite geometry.
"""
try: geoDim = geo.myDimension
except: raise TypeError("The given geometry does not state its dimensionality. "\
"Try using computeMagnitude() instead.")
if geoDim != 3:
raise TypeError("Volume can only be computed for three-dimensional geometries")
return _geometry.computeMagnitude(geo)
############################################
# Compute the distance between two geometries
def computeDistance(geo1, geo2):
......@@ -100,7 +143,7 @@ def computeDistance(geo1, geo2):
"""
Compute the minimum euclidian distance between geometries.
If the second argument (geo2) is a list of geometries, the minimum
distance of geo1 to the geometries of geo2 is returned.
distance of geo1 to the geometries contained in the list geo2 is returned.
"""
def doComputation(geo):
......@@ -120,7 +163,7 @@ def computeDistanceToBoundary(geo1, geo2):
Compute the minimum euclidian distance between a geometry and the
boundary of another geometry. The first argument is the geometry
for which the distance to the boundary of the geometry passed with
the second function argument.
the second function argument is to be computed.
"""
# try to use an overload for the given geometries, if none is found
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment