triangulation-type setting for non-triangulated polyhedral from iterator

This commit is contained in:
Thomas Krijnen
2024-09-18 19:25:37 +02:00
parent 748fcce3f5
commit 2554280e50
12 changed files with 320 additions and 154 deletions
+16
View File
@@ -78,3 +78,19 @@ std::istream& ifcopenshell::geometry::settings::operator>>(std::istream& in, Out
}
return in;
}
std::istream& ifcopenshell::geometry::settings::operator>>(std::istream& in, TriangulationMethod& v) {
std::string token;
in >> token;
boost::to_upper(token);
if (token == "TRIANGLE_MESH") {
v = TRIANGLE_MESH;
} else if (token == "POLYHEDRON_WITHOUT_HOLES") {
v = POLYHEDRON_WITHOUT_HOLES;
} else if (token == "POLYHEDRON_WITH_HOLES") {
v = POLYHEDRON_WITH_HOLES;
} else {
in.setstate(std::ios_base::failbit);
}
return in;
}
+18 -63
View File
@@ -378,12 +378,28 @@ namespace ifcopenshell {
static constexpr const char* const name = "model-rotation";
static constexpr const char* const description = "Applies an arbitrary quaternion rotation of form 'x,y,z,w' to all placements.";
};
enum TriangulationMethod {
TRIANGLE_MESH,
POLYHEDRON_WITHOUT_HOLES,
POLYHEDRON_WITH_HOLES
};
std::istream& operator>>(std::istream& in, TriangulationMethod& ioo);
struct TriangulationType : public SettingBase<TriangulationType, TriangulationMethod> {
static constexpr const char* const name = "triangulation-type";
static constexpr const char* const description = "Type of planar facet to be emitted";
static constexpr TriangulationMethod defaultvalue = TRIANGLE_MESH;
};
}
template <typename settings_t>
class IFC_GEOM_API SettingsContainer {
public:
typedef boost::variant<bool, int, double, std::string, std::set<int>, std::set<std::string>, std::vector<double>, IteratorOutputOptions, PiecewiseStepMethod, OutputDimensionalityTypes> value_variant_t;
typedef boost::variant<bool, int, double, std::string, std::set<int>, std::set<std::string>, std::vector<double>, IteratorOutputOptions, PiecewiseStepMethod, OutputDimensionalityTypes, TriangulationMethod> value_variant_t;
private:
settings_t settings;
@@ -470,73 +486,12 @@ namespace ifcopenshell {
};
class IFC_GEOM_API Settings : public SettingsContainer<
std::tuple<MesherLinearDeflection, MesherAngularDeflection, ReorientShells, LengthUnit, PlaneUnit, Precision, OutputDimensionality, LayersetFirst, DisableBooleanResult, NoWireIntersectionCheck, NoWireIntersectionTolerance, PrecisionFactor, DebugBooleanOperations, BooleanAttempt2d, WeldVertices, UseWorldCoords, UseMaterialNames, ConvertBackUnits, ContextIds, ContextTypes, ContextIdentifiers, IteratorOutput, DisableOpeningSubtractions, ApplyDefaultMaterials, DontEmitNormals, GenerateUvs, ApplyLayerSets, UseElementHierarchy, ValidateQuantities, EdgeArrows, BuildingLocalPlacement, SiteLocalPlacement, ForceSpaceTransparency, CircleSegments, KeepBoundingBoxes, PiecewiseStepType, PiecewiseStepParam, NoParallelMapping, ModelOffset, ModelRotation>
std::tuple<MesherLinearDeflection, MesherAngularDeflection, ReorientShells, LengthUnit, PlaneUnit, Precision, OutputDimensionality, LayersetFirst, DisableBooleanResult, NoWireIntersectionCheck, NoWireIntersectionTolerance, PrecisionFactor, DebugBooleanOperations, BooleanAttempt2d, WeldVertices, UseWorldCoords, UseMaterialNames, ConvertBackUnits, ContextIds, ContextTypes, ContextIdentifiers, IteratorOutput, DisableOpeningSubtractions, ApplyDefaultMaterials, DontEmitNormals, GenerateUvs, ApplyLayerSets, UseElementHierarchy, ValidateQuantities, EdgeArrows, BuildingLocalPlacement, SiteLocalPlacement, ForceSpaceTransparency, CircleSegments, KeepBoundingBoxes, PiecewiseStepType, PiecewiseStepParam, NoParallelMapping, ModelOffset, ModelRotation, TriangulationType>
>
{};
}
}
// namespace ifcopenshell {
// namespace geometry {
//
// class IFC_GEOM_API ConversionSettings {
// public:
// // Tolerances and settings for various geometrical operations:
// enum GeomValue {
// //
// // Default: 0.001m / 1mm
// GV_DEFLECTION_TOLERANCE,
//
// // The length unit used the creation of TopoDS_Shapes, primarily affects the
// // interpretation of IfcCartesianPoints and IfcVector magnitudes
// // DefaultL 1.0
// GV_LENGTH_UNIT,
// // The plane angle unit used for the creation of TopoDS_Shapes, primarily affects
// // the interpretation of IfcParamaterValues of IfcTrimmedCurves
// // Default: -1.0 (= not set, fist try degrees, then radians)
// GV_PLANEANGLE_UNIT,
// // The precision used in boolean operations, setting this value too low results
// // in artefacts and potentially modelling failures
// // Default: 0.00001 (obtained from IfcGeometricRepresentationContext if available)
// GV_PRECISION,
// // Whether to process shapes of type Face or higher (1) Wire or lower (-1) or all (0)
// GV_DIMENSIONALITY,
// GV_LAYERSET_FIRST,
// GV_DISABLE_BOOLEAN_RESULT,
// GV_NO_WIRE_INTERSECTION_CHECK,
// GV_PRECISION_FACTOR,
// GV_NO_WIRE_INTERSECTION_TOLERANCE,
// GV_DEBUG_BOOLEAN,
// GV_BOOLEAN_ATTEMPT_2D,
// NUM_SETTINGS
// };
//
// void setValue(GeomValue var, double value);
//
// double getValue(GeomValue var) const;
//
// private:
// std::array<double, NUM_SETTINGS> values_ = {
// /* deflection_tolerance = */ 0.001,
// // @todo make sure these 'read-only' variables work.
// /* minimal_face_area = */ std::numeric_limits<double>::quiet_NaN(),
// /* max_faces_to_orient = */ -1.0,
// /* ifc_length_unit = */ 1.0,
// /* ifc_planeangle_unit = */ -1.0,
// /* modelling_precision = */ 0.00001,
// /* dimensionality = */ 1.,
// /* layerset_first = */ -1.,
// /* disable_boolean_result = */ -1.
// /* no_wire_intersection_check = */ -1.,
// /* precision_factor = */ 10.,
// /* no_wire_intersection_tolerance = */ -1.,
// /* boolean_debug_setting = */ -1.,
// /* boolean_attempt_2d = */ 1.
// };
// };
// }
// }
// @todo find a place
namespace IfcGeom {
class IFC_GEOM_API geometry_exception : public std::exception {
+14 -14
View File
@@ -332,23 +332,23 @@ IfcGeom::Representation::Triangulation::Triangulation(const BRep& shape_model)
int surface_style_id = -1;
if (iit->hasStyle()) {
auto jt = std::find(_materials.begin(), _materials.end(), iit->StylePtr());
if (jt == _materials.end()) {
surface_style_id = (int)_materials.size();
_materials.push_back(iit->StylePtr());
auto jt = std::find(materials_.begin(), materials_.end(), iit->StylePtr());
if (jt == materials_.end()) {
surface_style_id = (int)materials_.size();
materials_.push_back(iit->StylePtr());
} else {
surface_style_id = (int)(jt - _materials.begin());
surface_style_id = (int)(jt - materials_.begin());
}
}
if (settings().get<ifcopenshell::geometry::settings::ApplyDefaultMaterials>().get() && surface_style_id == -1) {
const auto& material = IfcGeom::get_default_style(shape_model.entity());
auto mit = std::find(_materials.begin(), _materials.end(), material);
if (mit == _materials.end()) {
surface_style_id = (int)_materials.size();
_materials.push_back(material);
auto mit = std::find(materials_.begin(), materials_.end(), material);
if (mit == materials_.end()) {
surface_style_id = (int)materials_.size();
materials_.push_back(material);
} else {
surface_style_id = (int)(mit - _materials.begin());
surface_style_id = (int)(mit - materials_.begin());
}
}
@@ -393,7 +393,7 @@ int IfcGeom::Representation::Triangulation::addVertex(int item_id, int material_
const double X = convert ? (pX /unit_magnitude) : pX;
const double Y = convert ? (pY /unit_magnitude) : pY;
const double Z = convert ? (pZ /unit_magnitude) : pZ;
int i = (int)_verts.size() / 3;
int i = (int)verts_.size() / 3;
if (settings().get<ifcopenshell::geometry::settings::WeldVertices>().get()) {
const VertexKey key = std::make_tuple(item_id, material_index, X, Y, Z);
typename VertexKeyMap::const_iterator it = welds.find(key);
@@ -401,9 +401,9 @@ int IfcGeom::Representation::Triangulation::addVertex(int item_id, int material_
i = (int)(welds.size() + weld_offset_);
welds[key] = i;
}
_verts.push_back(X);
_verts.push_back(Y);
_verts.push_back(Z);
verts_.push_back(X);
verts_.push_back(Y);
verts_.push_back(Z);
return i;
}
+56 -34
View File
@@ -103,14 +103,20 @@ namespace IfcGeom {
typedef std::map<VertexKey, int> VertexKeyMap;
typedef std::pair<int, int> Edge;
std::vector<double> _verts;
std::vector<int> _faces;
std::vector<int> _edges;
std::vector<double> _normals;
std::vector<double> verts_;
// @nb only one of these is populated based on settings, we didn't want to go
// all in with templates or subtypes because of reduced ease of use.
std::vector<int> faces_;
std::vector<std::vector<int>> polyhedral_faces_without_holes_;
std::vector<std::vector<std::vector<int>>> polyhedral_faces_with_holes_;
std::vector<int> edges_;
std::vector<double> normals_;
std::vector<double> uvs_;
std::vector<int> _material_ids;
std::vector<ifcopenshell::geometry::taxonomy::style::ptr> _materials;
std::vector<int> _item_ids;
std::vector<int> material_ids_;
std::vector<ifcopenshell::geometry::taxonomy::style::ptr> materials_;
std::vector<int> item_ids_;
size_t weld_offset_;
VertexKeyMap welds;
@@ -120,15 +126,17 @@ namespace IfcGeom {
{}
public:
const std::vector<double>& verts() const { return _verts; }
const std::vector<int>& faces() const { return _faces; }
const std::vector<int>& edges() const { return _edges; }
const std::vector<double>& normals() const { return _normals; }
const std::vector<double>& verts() const { return verts_; }
const std::vector<int>& faces() const { return faces_; }
const std::vector<std::vector<int>>& polyhedral_faces_without_holes() const { return polyhedral_faces_without_holes_; }
const std::vector<std::vector<std::vector<int>>>& polyhedral_faces_with_holes() const { return polyhedral_faces_with_holes_; }
const std::vector<int>& edges() const { return edges_; }
const std::vector<double>& normals() const { return normals_; }
std::vector<double>& uvs() { return uvs_; }
const std::vector<double>& uvs() const { return uvs_; }
const std::vector<int>& material_ids() const { return _material_ids; }
const std::vector<ifcopenshell::geometry::taxonomy::style::ptr>& materials() const { return _materials; }
const std::vector<int>& item_ids() const { return _item_ids; }
const std::vector<int>& material_ids() const { return material_ids_; }
const std::vector<ifcopenshell::geometry::taxonomy::style::ptr>& materials() const { return materials_; }
const std::vector<int>& item_ids() const { return item_ids_; }
Triangulation(const BRep& shape_model);
@@ -146,14 +154,14 @@ namespace IfcGeom {
const std::vector<int>& item_ids
)
: Representation(settings, entity, id)
, _verts(verts)
, _faces(faces)
, _edges(edges)
, _normals(normals)
, verts_(verts)
, faces_(faces)
, edges_(edges)
, normals_(normals)
, uvs_(uvs)
, _material_ids(material_ids)
, _materials(materials)
, _item_ids(item_ids)
, material_ids_(material_ids)
, materials_(materials)
, item_ids_(item_ids)
{}
virtual ~Triangulation() {}
@@ -168,30 +176,44 @@ namespace IfcGeom {
int addVertex(int item_index, int material_index, double X, double Y, double Z);
void addNormal(double X, double Y, double Z) {
_normals.push_back(X);
_normals.push_back(Y);
_normals.push_back(Z);
normals_.push_back(X);
normals_.push_back(Y);
normals_.push_back(Z);
}
void addFace(int item_id, int style, int i0, int i1, int i2) {
_faces.push_back(i0);
_faces.push_back(i1);
_faces.push_back(i2);
faces_.push_back(i0);
faces_.push_back(i1);
faces_.push_back(i2);
_item_ids.push_back(item_id);
_material_ids.push_back(style);
item_ids_.push_back(item_id);
material_ids_.push_back(style);
}
void addFace(int item_id, int style, const std::vector<int>& outer_bound) {
polyhedral_faces_without_holes_.push_back(outer_bound);
item_ids_.push_back(item_id);
material_ids_.push_back(style);
}
void addFace(int item_id, int style, const std::vector<std::vector<int>>& bounds) {
polyhedral_faces_with_holes_.push_back(bounds);
item_ids_.push_back(item_id);
material_ids_.push_back(style);
}
void addEdge(int style, int i0, int i1) {
_edges.push_back(i0);
_edges.push_back(i1);
edges_.push_back(i0);
edges_.push_back(i1);
_material_ids.push_back(style);
material_ids_.push_back(style);
}
void registerEdge(int i0, int i1) {
_edges.push_back(i0);
_edges.push_back(i1);
edges_.push_back(i0);
edges_.push_back(i1);
}
void addEdge(int n1, int n2, std::map<std::pair<int, int>, int>& edgecount);
@@ -5,6 +5,7 @@
#include <BRepGProp.hxx>
#include <GProp_GProps.hxx>
#include <Geom_SphericalSurface.hxx>
#include <Geom_Plane.hxx>
#include "OpenCascadeConversionResult.h"
@@ -15,6 +16,12 @@
#include <Standard_Version.hxx>
#include <iostream>
#include <vector>
#include <unordered_map>
#include <tuple>
#include <algorithm>
#if OCC_VERSION_HEX >= 0x70600
#include <TopTools_FormatVersion.hxx>
#endif
@@ -24,6 +31,44 @@ using IfcGeom::OpaqueCoordinate;
using IfcGeom::NumberNativeDouble;
using IfcGeom::ConversionResultShape;
struct EdgeKey {
int v1, v2;
// These are not part of the hash or equality,
// but retained to easily created a directed
// graph of the original boundary edges. Since
// the boundary edges are exactly those with
// count=1 we don't need to worry about
// conflicting original vertex indices.
int ov1, ov2;
EdgeKey(int a, int b)
: ov1(a)
, ov2(b)
{
if (a < b) {
v1 = a;
v2 = b;
} else {
v1 = b;
v2 = a;
}
}
bool operator==(const EdgeKey& other) const {
return v1 == other.v1 && v2 == other.v2;
}
};
namespace std {
template <>
struct hash<EdgeKey> {
std::size_t operator()(const EdgeKey& ek) const {
return std::hash<int>()(ek.v1) ^ std::hash<int>()(ek.v2);
}
};
}
namespace {
// We bypass the conversion to gp_GTrsf, because it does not work
void taxonomy_transform(const Eigen::Matrix4d* m, gp_XYZ& xyz) {
@@ -35,6 +80,78 @@ namespace {
xyz.ChangeData()[2] = v2(2);
}
}
// Function to find boundary loops from triangles
std::vector<std::vector<int>> find_boundary_loops(const std::vector<double>& positions, const std::vector<std::tuple<int, int, int>>& triangles) {
std::unordered_map<EdgeKey, int> edge_count;
// Count how many triangles each edge belongs to
for (const auto& triangle : triangles) {
int v1, v2, v3;
std::tie(v1, v2, v3) = triangle;
edge_count[{v1, v2}]++;
edge_count[{v2, v3}]++;
edge_count[{v3, v1}]++;
}
// Boundary edges have count 1
std::vector<EdgeKey> boundary_edges;
for (auto& p : edge_count) {
if (p.second == 1) {
boundary_edges.push_back(p.first);
}
}
// We retained original directed edges so we build
// a mapping out of these directed edges.
std::unordered_map<int, int> vertex_successors;
for (const auto& e : boundary_edges) {
vertex_successors[e.ov1] = e.ov2;
}
std::vector<std::vector<int>> loops;
while (!vertex_successors.empty()) {
loops.emplace_back();
auto it = vertex_successors.begin();
loops.back() = { it->first, it->second };
vertex_successors.erase(it);
int current = loops.back().back();
while (!vertex_successors.empty() && current != loops.back().front()) {
auto next = vertex_successors[current];
if (loops.back().front() != next) {
loops.back().push_back(next);
}
vertex_successors.erase(current);
current = next;
}
}
// Sort the loops by smallest x-coord of their constituent positions
// In order to put the outermost loop in front
if (loops.size() > 1) {
std::vector<std::pair<double, size_t>> min_xs;
for (auto& l : loops) {
double min_x = std::numeric_limits<double>::infinity();
for (auto& i : l) {
const auto& x = positions[i * 3];
if (x < min_x) {
min_x = x;
}
}
min_xs.push_back({ min_x, min_xs.size() });
}
std::sort(min_xs.begin(), min_xs.end());
decltype(loops) loops_copy;
for (auto& p : min_xs) {
loops_copy.emplace_back(std::move(loops[p.second]));
}
std::swap(loops, loops_copy);
}
return loops;
}
}
void ifcopenshell::geometry::OpenCascadeShape::Triangulate(ifcopenshell::geometry::Settings settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int item_id, int surface_style_id) const {
@@ -71,6 +188,18 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(ifcopenshell::geometr
TopExp_Explorer exp;
for (exp.Init(shape_, TopAbs_FACE); exp.More(); exp.Next(), ++num_faces) {
TopoDS_Face face = TopoDS::Face(exp.Current());
size_t num_bounds = 0;
for (TopoDS_Iterator it(face); it.More(); it.Next(), ++num_bounds) {}
const bool is_planar = BRep_Tool::Surface(face) && BRep_Tool::Surface(face)->DynamicType() == STANDARD_TYPE(Geom_Plane);
const bool has_inner_bounds = num_bounds > 1;
const bool polyhedral_output_with_holes = settings.get<settings::TriangulationType>().get() == settings::POLYHEDRON_WITH_HOLES && is_planar;
const bool polyhedral_output_without_holes = settings.get<settings::TriangulationType>().get() == settings::POLYHEDRON_WITHOUT_HOLES && is_planar && !has_inner_bounds;
std::vector<std::tuple<int, int, int>> triangle_indices;
TopLoc_Location loc;
Handle_Poly_Triangulation tri = BRep_Tool::Triangulation(face, loc);
@@ -154,11 +283,21 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(ifcopenshell::geometr
_normals.push_back((float)normal.Z());
*/
t->addFace(item_id, surface_style_id, dict[n1], dict[n2], dict[n3]);
if (polyhedral_output_without_holes || polyhedral_output_with_holes) {
triangle_indices.push_back({ dict[n1], dict[n2], dict[n3] });
} else {
if (settings.get<settings::TriangulationType>().get() == settings::POLYHEDRON_WITHOUT_HOLES) {
t->addFace(item_id, surface_style_id, std::vector<int>{ dict[n1], dict[n2], dict[n3] });
} else if (settings.get<settings::TriangulationType>().get() == settings::POLYHEDRON_WITH_HOLES) {
t->addFace(item_id, surface_style_id, std::vector<std::vector<int>>{{ dict[n1], dict[n2], dict[n3] }});
} else {
t->addFace(item_id, surface_style_id, dict[n1], dict[n2], dict[n3]);
t->addEdge(dict[n1], dict[n2], edgecount);
t->addEdge(dict[n2], dict[n3], edgecount);
t->addEdge(dict[n3], dict[n1], edgecount);
t->addEdge(dict[n1], dict[n2], edgecount);
t->addEdge(dict[n2], dict[n3], edgecount);
t->addEdge(dict[n3], dict[n1], edgecount);
}
}
}
for (auto& p : edgecount) {
// @todo should be != 2?
@@ -172,6 +311,19 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(ifcopenshell::geometr
}
}
}
if (polyhedral_output_without_holes || polyhedral_output_with_holes) {
auto loops = find_boundary_loops(t->verts(), triangle_indices);
if (polyhedral_output_without_holes) {
if (!loops.empty() && !loops[0].empty()) {
t->addFace(item_id, surface_style_id, loops[0]);
}
} else {
if (!loops.empty()) {
t->addFace(item_id, surface_style_id, loops);
}
}
}
}
if (!t->normals().empty() && settings.get<settings::GenerateUvs>().get()) {
@@ -101,6 +101,9 @@ SETTING = Literal[
"piecewise-step-param",
"use-python-opencascade",
"no-parallel-mapping",
"triangulation-type",
"model-rotation",
"model-offset",
]
SERIALIZER_SETTING = Literal[
"use-element-names",
@@ -24,6 +24,7 @@ if os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) == sys.path[0]
# does not contain the built binary
sys.path[0:1] = []
import pytest
import ifcopenshell
import ifcopenshell.api.project
@@ -75,3 +76,8 @@ class IFC2X3:
ifcopenshell.api.pre_listeners = {}
ifcopenshell.api.post_listeners = {}
@pytest.fixture(autouse=True)
def file(request):
return ifcopenshell.open(os.path.join("test/fixtures", request.param))
+11 -1
View File
@@ -681,7 +681,17 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
%pythoncode %{
# Hide the getters with read-only property implementations
faces = property(faces)
faces_tri = property(faces)
polyhedral_faces_without_holes = property(polyhedral_faces_without_holes)
polyhedral_faces_with_holes = property(polyhedral_faces_with_holes)
def get_faces(self):
if self.faces_tri:
return self.faces_tri
elif self.polyhedral_faces_without_holes:
return self.polyhedral_faces_without_holes
else:
return self.polyhedral_faces_with_holes
faces = property(get_faces)
edges = property(edges)
material_ids = property(material_ids)
materials = property(materials)
+1 -21
View File
@@ -56,24 +56,6 @@ private:
%rename("add") addEntity;
%rename("remove") removeEntity;
%{
template<typename T>
struct is_std_vector : std::false_type {};
template<typename T, typename Alloc>
struct is_std_vector<std::vector<T, Alloc>> : std::true_type {};
template<typename T>
constexpr bool is_std_vector_v = is_std_vector<T>::value;
template<typename T>
struct is_std_vector_vector : std::false_type {};
template<typename T, typename Alloc, typename Alloc2>
struct is_std_vector_vector<std::vector<std::vector<T, Alloc>, Alloc2>> : std::true_type {};
template<typename T>
constexpr bool is_std_vector_vector_v = is_std_vector_vector<T>::value;
%}
class attribute_value_derived {};
%{
class attribute_value_derived {};
@@ -780,9 +762,7 @@ static IfcUtil::ArgumentType helper_fn_attribute_type(const IfcUtil::IfcBaseClas
PyObject* convert_cpp_attribute_to_python(AttributeValue arg) {
return arg.array_->apply_visitor([](auto& v){
using U = std::decay_t<decltype(v)>;
if constexpr (is_std_vector_vector_v<U>) {
return pythonize_vector2(v);
} else if constexpr (is_std_vector_v<U>) {
if constexpr (is_std_vector_v<U>) {
return pythonize_vector(v);
} else if constexpr (std::is_same_v<U, EnumerationReference>) {
return pythonize(std::string(v.value()));
+18
View File
@@ -148,6 +148,24 @@
#endif
%}
%{
template<typename T>
struct is_std_vector : std::false_type {};
template<typename T, typename Alloc>
struct is_std_vector<std::vector<T, Alloc>> : std::true_type {};
template<typename T>
constexpr bool is_std_vector_v = is_std_vector<T>::value;
template<typename T>
struct is_std_vector_vector : std::false_type {};
template<typename T, typename Alloc, typename Alloc2>
struct is_std_vector_vector<std::vector<std::vector<T, Alloc>, Alloc2>> : std::true_type {};
template<typename T>
constexpr bool is_std_vector_vector_v = is_std_vector_vector<T>::value;
%}
// Create docstrings for generated python code.
%feature("autodoc", "1");
+6 -12
View File
@@ -189,21 +189,15 @@
}
template <typename T>
PyObject* pythonize_vector(const std::vector<T>& v) {
PyObject* pythonize_vector(const T& v) {
const size_t size = v.size();
PyObject* pyobj = PyTuple_New(size);
for (size_t i = 0; i < size; ++i) {
PyTuple_SetItem(pyobj, i, pythonize(v[i]));
}
return pyobj;
}
template <typename T>
PyObject* pythonize_vector2(const std::vector< std::vector<T> >& v) {
const size_t size = v.size();
PyObject* pyobj = PyTuple_New(size);
for (size_t i = 0; i < size; ++i) {
PyTuple_SetItem(pyobj, i, pythonize_vector(v[i]));
if constexpr (is_std_vector_v<typename T::value_type>) {
PyTuple_SetItem(pyobj, i, pythonize_vector(v[i]));
} else {
PyTuple_SetItem(pyobj, i, pythonize(v[i]));
}
}
return pyobj;
}
+15 -5
View File
@@ -38,9 +38,7 @@
try {
$result = $1.array_->apply_visitor([](auto& v){
using U = std::decay_t<decltype(v)>;
if constexpr (is_std_vector_vector_v<U>) {
return pythonize_vector2(v);
} else if constexpr (is_std_vector_v<U>) {
if constexpr (is_std_vector_v<U>) {
return pythonize_vector(v);
} else if constexpr (std::is_same_v<U, EnumerationReference>) {
return pythonize(std::string(v.value()));
@@ -70,10 +68,22 @@
%define CREATE_VECTOR_TYPEMAP_OUT(template_type)
%typemap(out) std::vector<template_type> {
$result = pythonize_vector<template_type>($1);
$result = pythonize_vector<std::vector<template_type>>($1);
}
%typemap(out) const std::vector<template_type>& {
$result = pythonize_vector<template_type>(*$1);
$result = pythonize_vector<std::vector<template_type>>(*$1);
}
%typemap(out) std::vector<std::vector<template_type>> {
$result = pythonize_vector<std::vector<std::vector<template_type>>>($1);
}
%typemap(out) const std::vector<std::vector<template_type>>& {
$result = pythonize_vector<std::vector<std::vector<template_type>>>(*$1);
}
%typemap(out) std::vector<std::vector<std::vector<template_type>>> {
$result = pythonize_vector<std::vector<std::vector<std::vector<template_type>>>>($1);
}
%typemap(out) const std::vector<std::vector<std::vector<template_type>>>& {
$result = pythonize_vector<std::vector<std::vector<std::vector<template_type>>>>(*$1);
}
%enddef