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

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

Feature/python bindings

See merge request tools/frackit!63
parents 1c657a57 60640b13
......@@ -85,6 +85,22 @@ else ()
message(FATAL_ERROR "OpenCascade sources not found")
endif ()
# option to enable/disable python bindings (default: on)
option(FRACKIT_ENABLE_PYTHONBINDINGS "Enable python bindings for Frackit" ON)
# python and pybind11 for python bindings
find_package(PythonInterp 3)
find_package(pybind11)
if (FRACKIT_ENABLE_PYTHONBINDINGS AND NOT PYTHONINTERP_FOUND)
set(FRACKIT_ENABLE_PYTHONBINDINGS OFF)
message("Python interpreter not found. This is required to build the python library.")
elseif (FRACKIT_ENABLE_PYTHONBINDINGS AND NOT pybind11_FOUND)
set(FRACKIT_ENABLE_PYTHONBINDINGS OFF)
message("Pybind11 is required to build the python library.")
endif ()
# TODO: make sure pip is installed
# indicate the documentation build as an option and set it to ON by default
option(FRACKIT_BUILD_DOC "Build documentation" ON)
......@@ -118,4 +134,7 @@ add_subdirectory(appl)
add_subdirectory(cmake)
add_subdirectory(doc)
add_subdirectory(frackit)
if (FRACKIT_ENABLE_PYTHONBINDINGS)
add_subdirectory(python)
endif ()
add_subdirectory(test)
......@@ -8,4 +8,7 @@ add_subdirectory(io)
add_subdirectory(magnitude)
add_subdirectory(occ)
add_subdirectory(precision)
if (FRACKIT_ENABLE_PYTHONBINDINGS)
add_subdirectory(python)
endif ()
add_subdirectory(sampling)
......@@ -25,6 +25,7 @@
#define FRACKIT_COMMON_EXTRACT_DIMENSION_HH
#include <utility>
#include <memory>
#include <TopoDS_Shape.hxx>
#include <TopoDS_Vertex.hxx>
......@@ -35,6 +36,8 @@
#include <TopoDS_Solid.hxx>
#include <Standard.hxx>
#include <frackit/geometry/geometry.hh>
namespace Frackit {
/*!
......@@ -109,6 +112,13 @@ struct DimensionalityTraits<TopoDS_Solid>
: public DimensionalityTraits<TopoDS_Shape>
{ static constexpr int geometryDimension() { return 3; } };
/*!
* \brief The dimension of the abstract base class is not known.
* Thus, we provoke compiler errors when this is uses.
*/
template<> struct DimensionalityTraits<Geometry> {};
template<> struct DimensionalityTraits<std::shared_ptr<Geometry>> {};
/*!
* \brief Free function to return the dimension of a geometry.
*/
......
......@@ -30,6 +30,7 @@
#include <frackit/occ/breputilities.hh>
#include <frackit/common/extractctype.hh>
#include <frackit/common/extractdimension.hh>
#include <frackit/precision/defaultepsilon.hh>
#include <frackit/geometry/geometry.hh>
......@@ -45,7 +46,8 @@ namespace Frackit {
* \note The magnitude of points is always zero independent on if they
* are contained in the geometry or not.
*/
template<class Geometry, class Domain, std::enable_if_t<Geometry::myDimension() == 0, int> = 0>
template<class Geometry, class Domain,
std::enable_if_t<DimensionalityTraits<Geometry>::geometryDimension() == 0, int> = 0>
typename CoordinateTypeTraits<Geometry>::type
computeContainedMagnitude(const Geometry& geometry,
const Domain& domain)
......@@ -56,7 +58,8 @@ computeContainedMagnitude(const Geometry& geometry,
* \brief Returns the length of the part of a one-dimensional
* geometry that is contained in a domain geometry.
*/
template<class Geometry, class Domain, std::enable_if_t<Geometry::myDimension() == 1, int> = 0>
template<class Geometry, class Domain,
std::enable_if_t<DimensionalityTraits<Geometry>::geometryDimension() == 1, int> = 0>
typename CoordinateTypeTraits<Geometry>::type
computeContainedMagnitude(const Geometry& geometry,
const Domain& domain)
......@@ -69,7 +72,7 @@ computeContainedMagnitude(const Geometry& geometry,
if (isEdges.empty())
return 0.0;
typename Geometry::ctype size = 0.0;
typename CoordinateTypeTraits<Geometry>::type size = 0.0;
for (const auto& edge : isEdges)
size += computeMagnitude(edge);
return size;
......@@ -80,7 +83,8 @@ computeContainedMagnitude(const Geometry& geometry,
* \brief Returns the surface area of the part of a two-dimensional
* geometry that is contained in a domain geometry.
*/
template<class Geometry, class Domain, std::enable_if_t<Geometry::myDimension() == 2, int> = 0>
template<class Geometry, class Domain,
std::enable_if_t<DimensionalityTraits<Geometry>::geometryDimension() == 2, int> = 0>
typename CoordinateTypeTraits<Geometry>::type
computeContainedMagnitude(const Geometry& geometry,
const Domain& domain)
......@@ -93,11 +97,18 @@ computeContainedMagnitude(const Geometry& geometry,
if (isFaces.empty())
return 0.0;
typename Geometry::ctype size = 0.0;
typename CoordinateTypeTraits<Geometry>::type size = 0.0;
for (const auto& face : isFaces)
size += computeMagnitude(face,
defaultEpsilon(domain),
OCCUtilities::point(geometry.center()));
{
// TODO: Compute center point for TopoDS_Face?
if constexpr (std::is_same_v<Geometry, TopoDS_Face>)
size += computeMagnitude(face);
else
size += computeMagnitude(face,
defaultEpsilon(domain),
OCCUtilities::point(geometry.center()));
}
return size;
}
......
add_subdirectory(common)
add_subdirectory(geometry)
add_subdirectory(io)
add_subdirectory(magnitude)
add_subdirectory(occutilities)
add_subdirectory(precision)
add_subdirectory(sampling)
install(FILES
extractctype.hh
id.hh
math.hh
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/frackit/python/common)
// -*- 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_EXTRACT_CTYPE_HH
#define FRACKIT_PYTHON_EXTRACT_CTYPE_HH
#include <frackit/common/extractctype.hh>
#include <frackit/python/occutilities/brepwrapper.hh>
namespace Frackit::Python {
// helper struct to extract the underlying coordinate type of a
// geometry that provides compatibility with the brep wrappers
template<class Geo>
struct CoordinateTypeTraits
: public Frackit::CoordinateTypeTraits<Geo> {};
template<class S>
struct CoordinateTypeTraits<OCCUtilities::BRepWrapper<S>>
: public Frackit::CoordinateTypeTraits<S> {};
} // end namespace Frackit::Python
#endif
// -*- 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_COMMON_ID_HH
#define FRACKIT_PYTHON_COMMON_ID_HH
#include <pybind11/pybind11.h>
#include <pybind11/operators.h>
#include <frackit/common/id.hh>
namespace Frackit::Python {
namespace py = pybind11;
void registerId(py::module& module)
{
py::class_<Id> cls(module, "Id");
cls.def(py::init<std::size_t>());
cls.def("get", &Id::get, "return the id");
cls.def(py::self == Id());
}
} // end namespace Frackit::Python
#endif
// -*- 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_COMMON_MATH_HH
#define FRACKIT_PYTHON_COMMON_MATH_HH
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <frackit/geometry/vector.hh>
#include <frackit/geometry/direction.hh>
#include <frackit/common/math.hh>
namespace Frackit::Python {
namespace py = pybind11;
template<class ctype>
void registerMath(py::module& module)
{
module.def("toDegrees", &Frackit::toDegrees<ctype>, "Converts radians into degrees");
module.def("toRadians", &Frackit::toRadians<ctype>, "Converts degrees into radians");
// Register rotation overload for single vector
using namespace py::literals;
using Vector_3 = Vector<ctype, 3>;
using Direction_3 = Direction<ctype, 3>;
module.def("rotate",
py::overload_cast<Vector_3&, const Direction_3&, ctype>(&rotate<ctype>),
"Rotates a vector around the given axis & angle",
"vector"_a, "axis"_a, "angle"_a);
}
} // end namespace Frackit::Python
#endif
install(FILES
constraints.hh
entitynetwork.hh
networkbuilder.hh
networkbuilderwrappers.hh
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/frackit/python/entitynetwork)
// -*- 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_ENTITYNETWORK_CONSTRAINTS_HH
#define FRACKIT_PYTHON_ENTITYNETWORK_CONSTRAINTS_HH
#include <algorithm>
#include <vector>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <frackit/geometry/disk.hh>
#include <frackit/geometry/quadrilateral.hh>
#include <frackit/entitynetwork/constraints.hh>
#include <frackit/python/occutilities/brepwrapper.hh>
namespace Frackit::Python {
namespace py = pybind11;
namespace Detail {
// Wrapper class to provide compatibility with shape wrapper classes
template<class ST>
class EntityNetworkConstraintsWrapper
: public EntityNetworkConstraints<ST>
{
using ParentType = EntityNetworkConstraints<ST>;
public:
// evaluate the constraint between two geometries
template<class Geo1, class Geo2>
bool evaluateBinary(const Geo1& geo1, const Geo2& geo2) const
{
static constexpr auto isWrapper1 = OCCUtilities::IsBRepWrapper<Geo1>::value;
static constexpr auto isWrapper2 = OCCUtilities::IsBRepWrapper<Geo2>::value;
if constexpr (!isWrapper1 && !isWrapper2)
return ParentType::evaluate(geo1, geo2);
else if constexpr (!isWrapper1 && isWrapper2)
return ParentType::evaluate(geo1, geo2.get());
else if constexpr (isWrapper1 && !isWrapper2)
return ParentType::evaluate(geo1.get(), geo2);
else
return ParentType::evaluate(geo1.get(), geo2.get());
}
};
template<class Constraints>
void registerSetters(py::class_<Constraints>& cls)
{
cls.def("setMinDistance", &Constraints::setMinDistance,
"define the minimum distance between entities");
cls.def("setMinIntersectingAngle", &Constraints::setMinIntersectingAngle,
"define the minimum angle between intersecting entities");
cls.def("setMinIntersectionMagnitude", &Constraints::setMinIntersectionMagnitude,
"define the minimum magnitude of intersections between entities");
cls.def("setMinIntersectionDistance", &Constraints::setMinIntersectionDistance,
"define the minimum distance between an intersection and the boundaries of the intersecting entities");
cls.def("neglectMinDistance", &Constraints::neglectMinDistance,
"deactivate minimum distance constraint");
cls.def("neglectMinIntersectionAngle", &Constraints::neglectMinIntersectionAngle,
"deactivate minimum intersection angle constraint");
cls.def("neglectMinIntersectionMagnitude", &Constraints::neglectMinIntersectionMagnitude,
"deactivate minimum intersection magnitude constraint");
cls.def("neglectMinIntersectionDistance", &Constraints::neglectMinIntersectionDistance,
"deactivate constraint on minimum distance between intersections and entity boundaries");
cls.def("setIntersectionEpsilon", &Constraints::setIntersectionEpsilon,
"define a tolerance value to be used in intersection computations");
cls.def("setDefaultIntersectionEpsilon", &Constraints::setDefaultIntersectionEpsilon,
"restore the default tolerance for intersection computations");
cls.def("allowEquiDimensionalIntersections", &Constraints::allowEquiDimensionalIntersections,
"allows/prohibits entities to intersect in geometries of the same dimension");
}
template<class Geo1, class Geo2, class Constraints>
void registerBinaryEvaluator(py::class_<Constraints>& cls)
{
cls.def("evaluate",
&Constraints::template evaluateBinary<Geo1, Geo2>,
"evaluate the constraints between two entites");
}
template<class ctype, class Constraints>
void registerEvaluators(py::class_<Constraints>& cls)
{
// types for which this ought to be able to evaluate
using Disk = Frackit::Disk<ctype>;
using Quad_3 = Frackit::Quadrilateral<ctype, 3>;
using Face = OCCUtilities::FaceWrapper;
registerBinaryEvaluator<Disk, Disk>(cls);
registerBinaryEvaluator<Disk, Quad_3>(cls);
registerBinaryEvaluator<Disk, Face>(cls);
registerBinaryEvaluator<Quad_3, Quad_3>(cls);
registerBinaryEvaluator<Quad_3, Disk>(cls);
registerBinaryEvaluator<Quad_3, Face>(cls);
registerBinaryEvaluator<Face, Face>(cls);
registerBinaryEvaluator<Face, Disk>(cls);
registerBinaryEvaluator<Face, Quad_3>(cls);
}
} // end namespace Detail
template<class ctype>
void registerConstraints(py::module& module)
{
using Constraints = Detail::EntityNetworkConstraintsWrapper<ctype>;
py::class_<Constraints> cls(module, "_EntityNetworkConstraints");
cls.def(py::init());
Detail::registerSetters(cls);
Detail::registerEvaluators<ctype>(cls);
}
} // end namespace Frackit::Python
#endif
// -*- 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_ENTITY_NETWORK_HH
#define FRACKIT_PYTHON_ENTITY_NETWORK_HH
#include <pybind11/pybind11.h>
#include <frackit/entitynetwork/entitynetwork.hh>
#include <frackit/entitynetwork/containedentitynetwork.hh>
namespace Frackit::Python {
namespace py = pybind11;
namespace Detail {
void registerEntityNetwork(py::module& module)
{
py::class_<EntityNetwork>(module, "EntityNetwork");
}
void registerContainedEntityNetwork(py::module& module)
{
py::class_<ContainedEntityNetwork>(module, "ContainedEntityNetwork");
}
} // end namespace Detail
void registerEntityNetworks(py::module& module)
{
Detail::registerEntityNetwork(module);
Detail::registerContainedEntityNetwork(module);
}
} // end namespace Frackit::Python
#endif
// -*- 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_ENTITYNETWORK_BUILDER_HH
#define FRACKIT_PYTHON_ENTITYNETWORK_BUILDER_HH
#include <pybind11/pybind11.h>
// (currently) supported domain geometries
#include <frackit/geometry/box.hh>
#include <frackit/geometry/cylinder.hh>
// (currently) supported entity geometries
#include <frackit/geometry/disk.hh>
#include <frackit/geometry/quadrilateral.hh>
#include <frackit/python/occutilities/brepwrapper.hh>
#include <frackit/common/id.hh>
#include <frackit/entitynetwork/networkbuilder.hh>
#include "networkbuilderwrappers.hh"
namespace Frackit::Python {
namespace py = pybind11;
namespace Detail {
template<class Domain, class Builder, class... Bases>
void registerSubDomainAdder(py::class_<Builder, Bases...>& cls)
{
cls.def("addSubDomain", &Builder::template addSubDomain<Domain>, "add subdomain with the given id");
cls.def("addConfiningSubDomain", &Builder::template addConfiningSubDomain<Domain>, "add confining subdomain with the given id");
}
template<class Entity, class Builder, class... Bases>
void registerEntityAdder(py::class_<Builder, Bases...>& cls)
{
cls.def("addEntity",
&Builder::template addEntity<Entity>,
"add entity to the network");
}
template<class Entity, class Builder, class... Bases>
void registerSubDomainEntityAdder(py::class_<Builder, Bases...>& cls)
{
cls.def("addSubDomainEntity",
&Builder::template addSubDomainEntity<Entity>,
"add entity to be embedded in the subdomain with the given id");
}
template<class ctype, class Builder, class... Bases>
void registerSubDomainAdders(py::class_<Builder, Bases...>& cls)
{
registerSubDomainAdder< Box<ctype> >(cls);
registerSubDomainAdder< Cylinder<ctype> >(cls);
registerSubDomainAdder< OCCUtilities::SolidWrapper >(cls);
}
template<class ctype, class Wrapper, class... Bases>
void registerSubDomainEntityAdders(py::class_<Wrapper, Bases...>& cls)
{
registerSubDomainEntityAdder< Disk<ctype> >(cls);
registerSubDomainEntityAdder< Quadrilateral<ctype, 3> >(cls);
registerSubDomainEntityAdder< OCCUtilities::FaceWrapper >(cls);
}
template<class ctype, class Wrapper, class... Bases>
void registerEntityAdders(py::class_<Wrapper, Bases...>& cls)
{
registerEntityAdder< Disk<ctype> >(cls);
registerEntityAdder< Quadrilateral<ctype, 3> >(cls);
registerEntityAdder< OCCUtilities::FaceWrapper >(cls);
}
} // end namespace detail
template<class ctype>
void registerEntityNetworkBuilders(py::module& module)
{
// register common base class
using Base = EntityNetworkBuilderBase<ctype>;
py::class_<Base> base(module, "_EntityNetworkBuilderBase");
base.def("setEpsilon", &Base::setEpsilon, "define tolerance value for intersections");
base.def("setDefaultEpsilon", &Base::setDefaultEpsilon, "restore default tolerance value for intersections");
base.def("clear", &Base::clear, "clears all inserted data");
// register base classes for builders
using Builder = EntityNetworkBuilder<ctype>;
py::class_<Builder, Base> builder(module, "_EntityNetworkBuilder");
builder.def("build", &Builder::build, "build the network from the inserted entities");
using ContainedBuilder = ContainedEntityNetworkBuilder<ctype>;
py::class_<ContainedBuilder, Base> containedBuilder(module, "_ContainedEntityNetworkBuilder");
containedBuilder.def("build", &ContainedBuilder::build, "build the contained network from the inserted entities");
// register wrapper classes
using BuilderWrapper = Detail::EntityNetworkBuilderWrapper<ctype>;
py::class_<BuilderWrapper, Builder> builderWrapper(module, "_EntityNetworkBuilderWrapper");
builderWrapper.def(py::init());