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

Merge branch 'feature/python-distance-bindings' into 'master'

Feature/python distance bindings

See merge request tools/frackit!148
parents 43c95fcf 5fac1df6
......@@ -5,6 +5,7 @@ cylinder.hh
cylindersurface.hh
direction.hh
disk.hh
distance.hh
ellipsearc.hh
ellipse.hh
ellipticalgeometry.hh
......
// -*- 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_DISTANCE_HH
#define FRACKIT_PYTHON_GEOMETRY_DISTANCE_HH
#include <pybind11/pybind11.h>
#include <frackit/geometry/point.hh>
#include <frackit/geometry/segment.hh>
#include <frackit/python/occutilities/brepwrapper.hh>
#include <frackit/distance/distance.hh>
namespace Frackit::Python {
namespace py = pybind11;
namespace Detail {
template<class Geo1, class Geo2, class ctype>
ctype computeDistance(const Geo1& geo1, const Geo2& geo2)
{
return Frackit::computeDistance(OCCUtilities::getUnwrappedShape(geo1),
OCCUtilities::getUnwrappedShape(geo2));
}
} // end namespace Detail
template<class ctype>
void registerComputeDistance(py::module& module)
{
using namespace py::literals;
using Point = Frackit::Point<ctype, 3>;
using Segment = Frackit::Segment<ctype, 3>;
using ShapeWrapper = OCCUtilities::ShapeWrapper;
module.def("computeDistance",
py::overload_cast<const Point&, const Point&>(&Detail::computeDistance<Point, Point, ctype>),
"Returns the minimum euclidian distance between two points in 3d");
module.def("computeDistance",
py::overload_cast<const Segment&, const Point&>(&Detail::computeDistance<Segment, Point, ctype>),
"Returns the minimum euclidian distance between a segment and a point in 3d",
"segment"_a, "point"_a);
module.def("computeDistance",
py::overload_cast<const Point&, const Segment&>(&Detail::computeDistance<Point, Segment, ctype>),
"Returns the minimum euclidian distance between a point and a segment in 3d",
"point"_a, "segment"_a);
module.def("computeDistance",
py::overload_cast<const ShapeWrapper&, const ShapeWrapper&>(&Detail::computeDistance<ShapeWrapper, ShapeWrapper, ctype>),
"Returns the minimum euclidian distance between two generic shapes");
}
} // end namespace Frackit::Python
#endif
......@@ -40,6 +40,9 @@
#include <frackit/intersection/intersectiontraits.hh>
namespace Frackit::Python {
namespace py = pybind11;
namespace Detail {
//! for compatibility with BRepWrapper classes
......@@ -125,36 +128,19 @@ IntersectionResult<Geo1, Geo2> intersectAndConvert(const Geo1& geo1, const Geo2&
template<class Geo1, class Geo2>
IntersectionResult<Geo1, Geo2> intersect(const Geo1& geo1, const Geo2& geo2)
{
constexpr bool isWrapper1 = OCCUtilities::IsBRepWrapper<Geo1>::value;
constexpr bool isWrapper2 = OCCUtilities::IsBRepWrapper<Geo2>::value;
if constexpr (isWrapper1 && isWrapper2)
return intersectAndConvert(geo1.get(), geo2.get());
else if constexpr(isWrapper1 && !isWrapper2)
return intersectAndConvert(geo1.get(), geo2);
else if constexpr(!isWrapper1 && isWrapper2)
return intersectAndConvert(geo1, geo2.get());
else
return intersectAndConvert(geo1, geo2);
using namespace OCCUtilities;
return intersectAndConvert(getUnwrappedShape(geo1), getUnwrappedShape(geo2));
}
//! convert shape wrapper function arguments into shape representations and forward
template<class Geo1, class Geo2, class ctype>
IntersectionResult<Geo1, Geo2> intersect(const Geo1& geo1, const Geo2& geo2, ctype eps)
{
constexpr bool isWrapper1 = OCCUtilities::IsBRepWrapper<Geo1>::value;
constexpr bool isWrapper2 = OCCUtilities::IsBRepWrapper<Geo2>::value;
if constexpr (isWrapper1 && isWrapper2)
return intersectAndConvert(geo1.get(), geo2.get(), eps);
else if constexpr(isWrapper1 && !isWrapper2)
return intersectAndConvert(geo1.get(), geo2, eps);
else if constexpr(!isWrapper1 && isWrapper2)
return intersectAndConvert(geo1, geo2.get(), eps);
else
return intersectAndConvert(geo1, geo2, eps);
using namespace OCCUtilities;
return intersectAndConvert(getUnwrappedShape(geo1), getUnwrappedShape(geo2), eps);
}
template<class Geo1, class Geo2, class ctype>
void registerIntersectionFunction(py::module& module,
const std::string& name1,
......@@ -175,8 +161,6 @@ void registerIntersectionFunction(py::module& module,
} // end namespace Detail
namespace py = pybind11;
template<class ctype>
void registerIntersectionFunctions(py::module& module)
{
......
......@@ -134,6 +134,24 @@ struct IsBRepWrapper : public std::false_type {};
template<class S>
struct IsBRepWrapper<BRepWrapper<S>> : public std::true_type {};
// helper function to obtain the unwrapped geometry type
template<class Geo, std::enable_if_t<IsBRepWrapper<Geo>::value, int> = 0>
const typename Geo::Shape& getUnwrappedShape(const Geo& geo)
{ return geo.get(); }
template<class Geo, std::enable_if_t<!IsBRepWrapper<Geo>::value, int> = 0>
const Geo& getUnwrappedShape(const Geo& geo)
{ return geo; }
// helper function to obtain the wrapped geometry type
template<class Geo, std::enable_if_t<std::is_convertible_v<Geo, TopoDS_Shape>, int> = 0>
BRepWrapper<Geo> getWrappedShape(const Geo& geo)
{ return {geo}; }
template<class Geo, std::enable_if_t<!std::is_convertible_v<Geo, TopoDS_Shape>, int> = 0>
const Geo& getWrappedShape(const Geo& geo)
{ return geo; }
} // end namespace Frackit::Python::OCCUtilities
#endif
frackit_symlink_or_copy(FILES __init__.py)
pybind11_add_module(_geometry _geometry.cc)
target_link_libraries(_geometry PRIVATE ${OCC_LIBS})
......@@ -92,3 +92,22 @@ def Circle(*args, **kwargs):
if dim == 1: raiseGeometryConstructorException("circle", "notImplemented") # todo
elif dim == 2: raiseGeometryConstructorException("circle", "notImplemented") # todo
else: return Circle_3(*args, **kwargs)
############################################
# Compute the distance between two geometries
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.
"""
def doComputation(geo):
from frackit.occutilities import getShape, OCCShapeWrapper
try: return _geometry.computeDistance(geo1, geo)
except: return _geometry.computeDistance(OCCShapeWrapper(getShape(geo1)),
OCCShapeWrapper(getShape(geo)))
if not isinstance(geo2, list): return doComputation(geo2)
else: return min([doComputation(g) for g in geo2])
......@@ -39,6 +39,8 @@
#include <frackit/python/geometry/box.hh>
#include <frackit/python/geometry/sphere.hh>
#include <frackit/python/geometry/distance.hh>
PYBIND11_MODULE(_geometry, module)
{
Frackit::Python::registerGeometry(module);
......@@ -66,4 +68,7 @@ PYBIND11_MODULE(_geometry, module)
Frackit::Python::registerHollowCylinder<double>(module);
Frackit::Python::registerBox<double>(module);
Frackit::Python::registerSphere<double>(module);
// distance queries
Frackit::Python::registerComputeDistance<double>(module);
}
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