1
/***************************************************************************
2
* Copyright (c) 2007 Jürgen Riegel <juergen.riegel@web.de> *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 59 Temple Place, *
19
* Suite 330, Boston, MA 02111-1307, USA *
21
***************************************************************************/
24
#include "PreCompiled.h"
29
#include "ComplexGeoData.h"
30
#include "StringHasher.h"
32
// inclusion of the generated files (generated out of ComplexGeoDataPy.xml)
33
#include <App/ComplexGeoDataPy.h>
34
#include <App/ComplexGeoDataPy.cpp>
35
#include <App/StringHasherPy.h>
36
#include <App/StringIDPy.h>
37
#include <Base/BoundBoxPy.h>
38
#include <Base/MatrixPy.h>
39
#include <Base/PlacementPy.h>
40
#include "Base/PyWrapParseTupleAndKeywords.h"
41
#include <Base/VectorPy.h>
42
#include <Base/GeometryPyCXX.h>
47
// returns a string which represent the object e.g. when printed in python
48
std::string ComplexGeoDataPy::representation() const
50
return {"<ComplexGeoData object>"};
53
PyObject* ComplexGeoDataPy::getElementTypes(PyObject *args)
55
if (!PyArg_ParseTuple(args, ""))
58
std::vector<const char*> types = getComplexGeoDataPtr()->getElementTypes();
60
for (auto it : types) {
61
list.append(Py::String(it));
63
return Py::new_reference_to(list);
66
PyObject* ComplexGeoDataPy::countSubElements(PyObject *args)
69
if (!PyArg_ParseTuple(args, "s", &type))
73
unsigned long count = getComplexGeoDataPtr()->countSubElements(type);
74
return Py::new_reference_to(Py::Long(count));
77
PyErr_SetString(PyExc_RuntimeError, "failed to count sub-elements from object");
82
PyObject* ComplexGeoDataPy::getFacesFromSubElement(PyObject *args)
86
if (!PyArg_ParseTuple(args, "sk", &type, &index))
89
std::vector<Base::Vector3d> points;
90
std::vector<Base::Vector3d> normals;
91
std::vector<Data::ComplexGeoData::Facet> facets;
93
std::unique_ptr<Data::Segment> segm(getComplexGeoDataPtr()->getSubElement(type, index));
94
getComplexGeoDataPtr()->getFacesFromSubElement(segm.get(), points, normals, facets);
97
PyErr_SetString(PyExc_RuntimeError, "failed to get sub-element from object");
103
for (const auto & it : points)
104
vertex.append(Py::asObject(new Base::VectorPy(it)));
105
tuple.setItem(0, vertex);
107
for (const auto & it : facets) {
109
f.setItem(0,Py::Int(int(it.I1)));
110
f.setItem(1,Py::Int(int(it.I2)));
111
f.setItem(2,Py::Int(int(it.I3)));
114
tuple.setItem(1, facet);
115
return Py::new_reference_to(tuple);
118
PyObject* ComplexGeoDataPy::getLinesFromSubElement(PyObject *args)
122
if (!PyArg_ParseTuple(args, "si", &type, &index))
125
std::vector<Base::Vector3d> points;
126
std::vector<Data::ComplexGeoData::Line> lines;
128
std::unique_ptr<Data::Segment> segm(getComplexGeoDataPtr()->getSubElement(type, index));
129
getComplexGeoDataPtr()->getLinesFromSubElement(segm.get(), points, lines);
132
PyErr_SetString(PyExc_RuntimeError, "failed to get sub-element from object");
138
for (const auto & it : points)
139
vertex.append(Py::asObject(new Base::VectorPy(it)));
140
tuple.setItem(0, vertex);
142
for (const auto & it : lines) {
144
l.setItem(0,Py::Int((int)it.I1));
145
l.setItem(1,Py::Int((int)it.I2));
148
tuple.setItem(1, line);
149
return Py::new_reference_to(tuple);
152
PyObject* ComplexGeoDataPy::getPoints(PyObject *args)
154
double accuracy = 0.05;
155
if (!PyArg_ParseTuple(args, "d", &accuracy))
158
std::vector<Base::Vector3d> points;
159
std::vector<Base::Vector3d> normals;
161
getComplexGeoDataPtr()->getPoints(points, normals, accuracy);
164
PyErr_SetString(PyExc_RuntimeError, "failed to get sub-element from object");
170
for (const auto & it : points) {
171
vertex.append(Py::asObject(new Base::VectorPy(it)));
173
tuple.setItem(0, vertex);
176
for (const auto & it : normals) {
177
normal.append(Py::asObject(new Base::VectorPy(it)));
179
tuple.setItem(1, normal);
180
return Py::new_reference_to(tuple);
183
PyObject* ComplexGeoDataPy::getLines(PyObject *args)
185
double accuracy = 0.05;
186
if (!PyArg_ParseTuple(args, "d", &accuracy))
189
std::vector<Base::Vector3d> points;
190
std::vector<Data::ComplexGeoData::Line> lines;
192
getComplexGeoDataPtr()->getLines(points, lines, accuracy);
195
PyErr_SetString(PyExc_RuntimeError, "failed to get sub-element from object");
201
for (const auto & it : points)
202
vertex.append(Py::asObject(new Base::VectorPy(it)));
203
tuple.setItem(0, vertex);
205
for (const auto & it : lines) {
207
l.setItem(0,Py::Int((int)it.I1));
208
l.setItem(1,Py::Int((int)it.I2));
211
tuple.setItem(1, line);
212
return Py::new_reference_to(tuple);
215
PyObject* ComplexGeoDataPy::getFaces(PyObject *args)
217
double accuracy = 0.05;
218
if (!PyArg_ParseTuple(args, "d", &accuracy))
221
std::vector<Base::Vector3d> points;
222
std::vector<Data::ComplexGeoData::Facet> facets;
224
getComplexGeoDataPtr()->getFaces(points, facets, accuracy);
227
PyErr_SetString(PyExc_RuntimeError, "failed to get sub-element from object");
233
for (const auto & it : points)
234
vertex.append(Py::asObject(new Base::VectorPy(it)));
235
tuple.setItem(0, vertex);
237
for (const auto & it : facets) {
239
f.setItem(0,Py::Int((int)it.I1));
240
f.setItem(1,Py::Int((int)it.I2));
241
f.setItem(2,Py::Int((int)it.I3));
244
tuple.setItem(1, facet);
245
return Py::new_reference_to(tuple);
248
PyObject* ComplexGeoDataPy::applyTranslation(PyObject *args)
251
if (!PyArg_ParseTuple(args, "O!", &(Base::VectorPy::Type),&obj))
255
Base::Vector3d move = static_cast<Base::VectorPy*>(obj)->value();
256
getComplexGeoDataPtr()->applyTranslation(move);
260
PyErr_SetString(PyExc_RuntimeError, "failed to apply rotation");
265
PyObject* ComplexGeoDataPy::applyRotation(PyObject *args)
268
if (!PyArg_ParseTuple(args, "O!", &(Base::RotationPy::Type),&obj))
272
Base::Rotation rot = static_cast<Base::RotationPy*>(obj)->value();
273
getComplexGeoDataPtr()->applyRotation(rot);
277
PyErr_SetString(PyExc_RuntimeError, "failed to apply rotation");
282
PyObject* ComplexGeoDataPy::transformGeometry(PyObject *args)
285
if (!PyArg_ParseTuple(args, "O!", &(Base::MatrixPy::Type),&obj))
289
Base::Matrix4D mat = static_cast<Base::MatrixPy*>(obj)->value();
290
getComplexGeoDataPtr()->transformGeometry(mat);
294
PyErr_SetString(PyExc_RuntimeError, "failed to transform geometry");
299
PyObject* ComplexGeoDataPy::getElementName(PyObject* args)
303
if (!PyArg_ParseTuple(args, "s|i", &input, &direction)) {
307
Data::MappedElement res = getComplexGeoDataPtr()->getElementName(input);
309
if (direction == 1) {
310
return Py::new_reference_to(Py::String(res.name.appendToBuffer(s)));
312
else if (direction == 0) {
313
return Py::new_reference_to(Py::String(res.index.appendToStringBuffer(s)));
315
else if (Data::IndexedName(input)) {
316
return Py::new_reference_to(Py::String(res.name.appendToBuffer(s)));
319
return Py::new_reference_to(Py::String(res.index.appendToStringBuffer(s)));
323
PyObject* ComplexGeoDataPy::getElementIndexedName(PyObject* args)
326
PyObject* returnID = Py_False;
327
if (!PyArg_ParseTuple(args, "s|O", &input, &returnID)) {
332
Data::MappedElement res =
333
getComplexGeoDataPtr()->getElementName(input, PyObject_IsTrue(returnID) ? &ids : nullptr);
335
Py::String name(res.index.appendToStringBuffer(s));
336
if (!PyObject_IsTrue(returnID)) {
337
return Py::new_reference_to(name);
341
for (auto& id : ids) {
342
list.append(Py::Long(id.value()));
344
return Py::new_reference_to(Py::TupleN(name, list));
347
PyObject* ComplexGeoDataPy::getElementMappedName(PyObject* args)
350
PyObject* returnID = Py_False;
351
if (!PyArg_ParseTuple(args, "s|O", &input, &returnID)) {
356
Data::MappedElement res =
357
getComplexGeoDataPtr()->getElementName(input, PyObject_IsTrue(returnID) ? &ids : nullptr);
359
Py::String name(res.name.appendToBuffer(s));
360
if (!PyObject_IsTrue(returnID)) {
361
return Py::new_reference_to(name);
365
for (auto& id : ids) {
366
list.append(Py::Long(id.value()));
368
return Py::new_reference_to(Py::TupleN(name, list));
371
PyObject* ComplexGeoDataPy::setElementName(PyObject* args, PyObject* kwds)
374
const char* name = 0;
375
const char* postfix = 0;
377
PyObject* pySid = Py_None;
378
PyObject* overwrite = Py_False;
380
const std::array<const char *,7> kwlist = {"element", "name", "postfix", "overwrite", "sid", "tag", nullptr};
381
if (!Wrapped_ParseTupleAndKeywords(args,
394
if (pySid != Py_None) {
395
if (PyObject_TypeCheck(pySid, &App::StringIDPy::Type)) {
396
sids.push_back(static_cast<App::StringIDPy*>(pySid)->getStringIDPtr());
398
else if (PySequence_Check(pySid)) {
399
Py::Sequence seq(pySid);
400
for (auto it = seq.begin(); it != seq.end(); ++it) {
401
auto ptr = (*it).ptr();
402
if (PyObject_TypeCheck(ptr, &App::StringIDPy::Type)) {
403
sids.push_back(static_cast<App::StringIDPy*>(ptr)->getStringIDPtr());
406
throw Py::TypeError("expect StringID in sid sequence");
411
throw Py::TypeError("expect sid to contain either StringID or sequence of StringID");
416
Data::IndexedName index(element, getComplexGeoDataPtr()->getElementTypes());
417
Data::MappedName mapped = Data::MappedName::fromRawData(name);
418
std::ostringstream ss;
419
ElementMapPtr map = getComplexGeoDataPtr()->resetElementMap();
420
map->encodeElementName(getComplexGeoDataPtr()->elementType(index),
427
Data::MappedName res =
428
map->setElementName(index, mapped, tag, &sids, PyObject_IsTrue(overwrite));
429
return Py::new_reference_to(Py::String(res.toString(0)));
434
Py::Object ComplexGeoDataPy::getHasher() const
436
auto self = getComplexGeoDataPtr();
440
return Py::Object(self->Hasher->getPyObject(), true);
443
Py::Dict ComplexGeoDataPy::getElementMap() const
447
for (auto& v : getComplexGeoDataPtr()->getElementMap()) {
449
ret.setItem(v.name.toString(0), Py::String(v.index.appendToStringBuffer(s)));
454
void ComplexGeoDataPy::setElementMap(Py::Dict dict)
456
std::vector<Data::MappedElement> map;
457
const auto& types = getComplexGeoDataPtr()->getElementTypes();
458
for (auto it = dict.begin(); it != dict.end(); ++it) {
459
const auto& value = *it;
460
if (!value.first.isString() || !value.second.isString()) {
461
throw Py::TypeError("expect only strings in the dict");
463
map.emplace_back(Data::MappedName(value.first.as_string().c_str()),
464
Data::IndexedName(Py::Object(value.second).as_string().c_str(), types));
466
getComplexGeoDataPtr()->setElementMap(map);
469
Py::Dict ComplexGeoDataPy::getElementReverseMap() const
473
for (auto& v : getComplexGeoDataPtr()->getElementMap()) {
475
auto value = ret[Py::String(v.index.appendToStringBuffer(s))];
476
Py::Object item(value);
479
value = Py::String(v.name.appendToBuffer(s));
481
else if (item.isList()) {
484
list.append(Py::String(v.name.appendToBuffer(s)));
490
list.append(Py::String(v.name.appendToBuffer(s)));
497
Py::Int ComplexGeoDataPy::getElementMapSize() const
499
return Py::Int((long)getComplexGeoDataPtr()->getElementMapSize());
502
void ComplexGeoDataPy::setHasher(Py::Object obj)
504
auto self = getComplexGeoDataPtr();
507
self->Hasher = App::StringHasherRef();
508
self->resetElementMap();
511
else if (PyObject_TypeCheck(obj.ptr(), &App::StringHasherPy::Type)) {
512
App::StringHasherRef ref(
513
static_cast<App::StringHasherPy*>(obj.ptr())->getStringHasherPtr());
514
if (self->Hasher != ref) {
516
self->resetElementMap();
520
throw Py::TypeError("invalid type");
524
Py::Object ComplexGeoDataPy::getBoundBox() const
526
return Py::BoundingBox(getComplexGeoDataPtr()->getBoundBox());
529
Py::Object ComplexGeoDataPy::getCenterOfGravity() const
531
Base::Vector3d center;
532
if (getComplexGeoDataPtr()->getCenterOfGravity(center))
533
return Py::Vector(center);
534
throw Py::RuntimeError("Cannot get center of gravity");
537
Py::Object ComplexGeoDataPy::getPlacement() const
539
return Py::Placement(getComplexGeoDataPtr()->getPlacement());
542
void ComplexGeoDataPy::setPlacement(Py::Object arg)
544
PyObject* p = arg.ptr();
545
if (PyObject_TypeCheck(p, &(Base::PlacementPy::Type))) {
546
Base::Placement* trf = static_cast<Base::PlacementPy*>(p)->getPlacementPtr();
547
getComplexGeoDataPtr()->setPlacement(*trf);
550
std::string error = std::string("type must be 'Placement', not ");
551
error += p->ob_type->tp_name;
552
throw Py::TypeError(error);
556
Py::String ComplexGeoDataPy::getElementMapVersion() const
558
return Py::String(getComplexGeoDataPtr()->getElementMapVersion());
562
Py::Int ComplexGeoDataPy::getTag() const
564
return Py::Int(getComplexGeoDataPtr()->Tag);
567
void ComplexGeoDataPy::setTag(Py::Int tag)
569
getComplexGeoDataPtr()->Tag = tag;
572
PyObject* ComplexGeoDataPy::getCustomAttributes(const char* attr) const
574
// Support for backward compatibility
575
if (strcmp(attr, "Matrix") == 0) {
576
Py::Matrix mat(getComplexGeoDataPtr()->getTransform());
577
return Py::new_reference_to(mat);
582
int ComplexGeoDataPy::setCustomAttributes(const char* attr, PyObject* obj)
584
// Support for backward compatibility
585
if (strcmp(attr, "Matrix") == 0) {
586
if (PyObject_TypeCheck(obj, &(Base::MatrixPy::Type))) {
587
Base::Matrix4D mat = static_cast<Base::MatrixPy*>(obj)->value();
588
getComplexGeoDataPtr()->setTransform(mat);
592
std::string error = std::string("type must be 'Matrix', not ");
593
error += obj->ob_type->tp_name;
594
throw Py::TypeError(error);