From ce67325616d238c0dd60561bc500b16c6f5f894f Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 11 May 2017 11:20:21 +0200 Subject: [PATCH 01/10] add method to get ancestors of a sub-shape --- src/Mod/Part/App/TopoShapePy.xml | 7 +++ src/Mod/Part/App/TopoShapePyImp.cpp | 69 +++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/src/Mod/Part/App/TopoShapePy.xml b/src/Mod/Part/App/TopoShapePy.xml index 303bd2e6fd..b9a7acaad8 100644 --- a/src/Mod/Part/App/TopoShapePy.xml +++ b/src/Mod/Part/App/TopoShapePy.xml @@ -283,6 +283,13 @@ Return a list of sub-shapes that are direct children of this shape. + + + ancestorsOfType(shape, shape type) -> list +For a sub-shape of this shape get its ancestors of a type. + + + Removes internal wires (also holes) from the shape. diff --git a/src/Mod/Part/App/TopoShapePyImp.cpp b/src/Mod/Part/App/TopoShapePyImp.cpp index 3ac01ac2a5..8f2aab8d40 100644 --- a/src/Mod/Part/App/TopoShapePyImp.cpp +++ b/src/Mod/Part/App/TopoShapePyImp.cpp @@ -1218,6 +1218,75 @@ PyObject* TopoShapePy::childShapes(PyObject *args) } } +namespace Part { +std::vector buildShapeEnumTypeMap() +{ + std::vector typeMap; + typeMap.push_back(&TopoShapeCompoundPy::Type); //TopAbs_COMPOUND + typeMap.push_back(&TopoShapeCompSolidPy::Type); //TopAbs_COMPSOLID + typeMap.push_back(&TopoShapeSolidPy::Type); //TopAbs_SOLID + typeMap.push_back(&TopoShapeShellPy::Type); //TopAbs_SHELL + typeMap.push_back(&TopoShapeFacePy::Type); //TopAbs_FACE + typeMap.push_back(&TopoShapeWirePy::Type); //TopAbs_WIRE + typeMap.push_back(&TopoShapeEdgePy::Type); //TopAbs_EDGE + typeMap.push_back(&TopoShapeVertexPy::Type); //TopAbs_VERTEX + typeMap.push_back(&TopoShapePy::Type); //TopAbs_SHAPE + return typeMap; +} +} + +PyObject* TopoShapePy::ancestorsOfType(PyObject *args) +{ + PyObject *pcObj; + PyObject *type; + if (!PyArg_ParseTuple(args, "O!O!", &(TopoShapePy::Type), &pcObj, &PyType_Type, &type)) + return NULL; + + try { + const TopoDS_Shape& model = getTopoShapePtr()->getShape(); + const TopoDS_Shape& shape = static_cast(pcObj)-> + getTopoShapePtr()->getShape(); + if (model.IsNull() || shape.IsNull()) { + PyErr_SetString(PyExc_ValueError, "Shape is null"); + return NULL; + } + + static std::vector typeMap = buildShapeEnumTypeMap(); + PyTypeObject* pyType = reinterpret_cast(type); + TopAbs_ShapeEnum shapetype = TopAbs_SHAPE; + for (auto it = typeMap.begin(); it != typeMap.end(); ++it) { + if (PyType_IsSubtype(pyType, *it)) { + auto index = std::distance(typeMap.begin(), it); + shapetype = static_cast(index); + break; + } + } + + TopTools_IndexedDataMapOfShapeListOfShape mapOfShapeShape; + TopExp::MapShapesAndAncestors(model, shape.ShapeType(), shapetype, mapOfShapeShape); + const TopTools_ListOfShape& ancestors = mapOfShapeShape.FindFromKey(shape); + + Py::List list; + std::set hashes; + TopTools_ListIteratorOfListOfShape it(ancestors); + for (; it.More(); it.Next()) { + // make sure to avoid duplicates + Standard_Integer code = it.Value().HashCode(INT_MAX); + if (hashes.find(code) == hashes.end()) { + list.append(shape2pyshape(it.Value())); + hashes.insert(code); + } + } + + return Py::new_reference_to(list); + } + catch (Standard_Failure) { + Handle(Standard_Failure) e = Standard_Failure::Caught(); + PyErr_SetString(PartExceptionOCCError, e->GetMessageString()); + return NULL; + } +} + PyObject* TopoShapePy::removeInternalWires(PyObject *args) { double minArea; From e6202f46e97542a2e72d58823eabb4f5b8821136 Mon Sep 17 00:00:00 2001 From: looooo Date: Thu, 11 May 2017 09:55:40 +0200 Subject: [PATCH 02/10] py3: App: files D-Z ported to python3 issue 0000995 diff to py3-branch will remain in the following files in src/App: - ExtensionContainer.cpp - FeaturePythonPyImp.h +.inl most likely these files depend on Tools and Base --- src/App/DocumentObjectPyImp.cpp | 11 +- src/App/DocumentPyImp.cpp | 23 ++- src/App/FeaturePythonPyImp.h | 25 ++++ src/App/ObjectIdentifier.cpp | 12 +- src/App/PropertyContainerPyImp.cpp | 4 + src/App/PropertyFile.cpp | 72 ++++++++++ src/App/PropertyGeo.cpp | 20 +++ src/App/PropertyPythonObject.cpp | 8 ++ src/App/PropertyStandard.cpp | 218 +++++++++++++++++++++++++++-- src/App/PropertyUnits.cpp | 16 ++- 10 files changed, 389 insertions(+), 20 deletions(-) diff --git a/src/App/DocumentObjectPyImp.cpp b/src/App/DocumentObjectPyImp.cpp index b14d2f3fab..6dda3c9d16 100644 --- a/src/App/DocumentObjectPyImp.cpp +++ b/src/App/DocumentObjectPyImp.cpp @@ -267,25 +267,34 @@ PyObject* DocumentObjectPy::setExpression(PyObject * args) if (Py::Object(expr).isNone()) getDocumentObjectPtr()->setExpression(p, boost::shared_ptr()); +#if PY_MAJOR_VERSION >= 3 + else if (PyUnicode_Check(expr)) { + const char * exprStr = PyUnicode_AsUTF8(expr); +#else else if (PyString_Check(expr)) { const char * exprStr = PyString_AsString(expr); +#endif boost::shared_ptr shared_expr(ExpressionParser::parse(getDocumentObjectPtr(), exprStr)); getDocumentObjectPtr()->setExpression(p, shared_expr, comment); } else if (PyUnicode_Check(expr)) { +#if PY_MAJOR_VERSION >= 3 + std::string exprStr = PyUnicode_AsUTF8(expr); +#else PyObject* unicode = PyUnicode_AsEncodedString(expr, "utf-8", 0); if (unicode) { std::string exprStr = PyString_AsString(unicode); - Py_DECREF(unicode); boost::shared_ptr shared_expr(ExpressionParser::parse(getDocumentObjectPtr(), exprStr.c_str())); getDocumentObjectPtr()->setExpression(p, shared_expr, comment); + Py_DECREF(unicode); } else { // utf-8 encoding failed return 0; } +#endif } else throw Py::TypeError("String or None expected."); diff --git a/src/App/DocumentPyImp.cpp b/src/App/DocumentPyImp.cpp index dccaff2e77..d69f4e6958 100644 --- a/src/App/DocumentPyImp.cpp +++ b/src/App/DocumentPyImp.cpp @@ -211,7 +211,11 @@ PyObject* DocumentPy::exportGraphviz(PyObject * args) else { std::stringstream str; getDocumentPtr()->exportGraphviz(str); +#if PY_MAJOR_VERSION >= 3 + return PyUnicode_FromString(str.str().c_str()); +#else return PyString_FromString(str.str().c_str()); +#endif } } @@ -326,6 +330,13 @@ PyObject* DocumentPy::openTransaction(PyObject *args) if (!PyArg_ParseTuple(args, "|O",&value)) return NULL; // NULL triggers exception std::string cmd; + + +#if PY_MAJOR_VERSION >= 3 + if (PyUnicode_Check(value)) { + cmd = PyUnicode_AsUTF8(value); + } +#else if (PyUnicode_Check(value)) { PyObject* unicode = PyUnicode_AsLatin1String(value); cmd = PyString_AsString(unicode); @@ -334,7 +345,10 @@ PyObject* DocumentPy::openTransaction(PyObject *args) else if (PyString_Check(value)) { cmd = PyString_AsString(value); } - getDocumentPtr()->openTransaction(cmd.c_str()); +#endif + else + return NULL; + getDocumentPtr()->openTransaction(cmd.c_str()); Py_Return; } @@ -521,9 +535,10 @@ Py::Int DocumentPy::getUndoMode(void) const void DocumentPy::setUndoMode(Py::Int arg) { - getDocumentPtr()->setUndoMode(arg); + getDocumentPtr()->setUndoMode(arg); } + Py::Int DocumentPy::getUndoRedoMemSize(void) const { return Py::Int((long)getDocumentPtr()->getUndoMemSize()); @@ -591,12 +606,16 @@ PyObject* DocumentPy::getTempFileName(PyObject *args) std::string string; if (PyUnicode_Check(value)) { +#if PY_MAJOR_VERSION >= 3 + string = PyUnicode_AsUTF8(value); +#else PyObject* unicode = PyUnicode_AsUTF8String(value); string = PyString_AsString(unicode); Py_DECREF(unicode); } else if (PyString_Check(value)) { string = PyString_AsString(value); +#endif } else { std::string error = std::string("type must be a string!"); diff --git a/src/App/FeaturePythonPyImp.h b/src/App/FeaturePythonPyImp.h index d040ea01b6..47fafa6f92 100644 --- a/src/App/FeaturePythonPyImp.h +++ b/src/App/FeaturePythonPyImp.h @@ -37,6 +37,29 @@ virtual ~_class_(); \ }; +#if PY_MAJOR_VERSION >= 3 +#define PYTHON_TYPE_IMP(_class_, _subclass_) \ + PyTypeObject _class_::Type = { \ + PyVarObject_HEAD_INIT(&PyType_Type, 0) \ + ""#_class_"", \ + sizeof(_class_), \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + Py_TPFLAGS_BASETYPE|Py_TPFLAGS_DEFAULT, \ + ""#_class_"", \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + &_subclass_::Type, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \ + }; \ + _class_::_class_(Base::BaseClass *pcObject, PyTypeObject *T) \ + : _subclass_(reinterpret_cast<_subclass_::PointerType>(pcObject), T) \ + { \ + } \ + _class_::~_class_() \ + { \ + } + +#else + #define PYTHON_TYPE_IMP(_class_, _subclass_) \ PyTypeObject _class_::Type = { \ PyObject_HEAD_INIT(&PyType_Type) \ @@ -58,6 +81,8 @@ { \ } +#endif + namespace App { diff --git a/src/App/ObjectIdentifier.cpp b/src/App/ObjectIdentifier.cpp index 9712220c71..b7b51ce3ef 100644 --- a/src/App/ObjectIdentifier.cpp +++ b/src/App/ObjectIdentifier.cpp @@ -1035,18 +1035,28 @@ boost::any ObjectIdentifier::getValue() const if (!pyvalue) throw Base::RuntimeError("Failed to get property value."); - +#if PY_MAJOR_VERSION < 3 if (PyInt_Check(pyvalue)) return boost::any(PyInt_AsLong(pyvalue)); +#else + if (PyLong_Check(pyvalue)) + return boost::any(PyLong_AsLong(pyvalue)); +#endif else if (PyFloat_Check(pyvalue)) return boost::any(PyFloat_AsDouble(pyvalue)); +#if PY_MAJOR_VERSION < 3 else if (PyString_Check(pyvalue)) return boost::any(PyString_AsString(pyvalue)); +#endif else if (PyUnicode_Check(pyvalue)) { PyObject * s = PyUnicode_AsUTF8String(pyvalue); destructor d2(s); +#if PY_MAJOR_VERSION >= 3 + return boost::any(PyUnicode_AsUTF8(s)); +#else return boost::any(PyString_AsString(s)); +#endif } else if (PyObject_TypeCheck(pyvalue, &Base::QuantityPy::Type)) { Base::QuantityPy * qp = static_cast(pyvalue); diff --git a/src/App/PropertyContainerPyImp.cpp b/src/App/PropertyContainerPyImp.cpp index 3fed9a4fa1..6ff2a4e6c8 100644 --- a/src/App/PropertyContainerPyImp.cpp +++ b/src/App/PropertyContainerPyImp.cpp @@ -244,7 +244,11 @@ PyObject *PropertyContainerPy::getCustomAttributes(const char* attr) const PyObject *dict = PyDict_New(); if (dict) { for ( std::map::iterator it = Map.begin(); it != Map.end(); ++it ) +#if PY_MAJOR_VERSION >= 3 + PyDict_SetItem(dict, PyUnicode_FromString(it->first.c_str()), PyUnicode_FromString("")); +#else PyDict_SetItem(dict, PyString_FromString(it->first.c_str()), PyString_FromString("")); +#endif if (PyErr_Occurred()) { Py_DECREF(dict); dict = NULL; diff --git a/src/App/PropertyFile.cpp b/src/App/PropertyFile.cpp index 1be0b2c60c..cf34b69b06 100644 --- a/src/App/PropertyFile.cpp +++ b/src/App/PropertyFile.cpp @@ -253,8 +253,55 @@ PyObject *PropertyFileIncluded::getPyObject(void) return p; } +#if PY_MAJOR_VERSION >= 3 +namespace App { +const char* getNameFromFile(PyObject* value) +{ + const char* string = 0; + PyObject *oname = PyObject_GetAttrString (value, "name"); + if (oname) { + if (PyUnicode_Check (oname)) { + string = PyUnicode_AsUTF8 (oname); + } + else if (PyBytes_Check (oname)) { + string = PyBytes_AsString (oname); + } + Py_DECREF (oname); + } + + if (!string) + throw Base::TypeError("Unable to get filename"); + return string; +} + + + +bool isIOFile(PyObject* file) +{ + PyObject* io = PyImport_ImportModule("io"); + PyObject* IOBase_Class = PyObject_GetAttrString(io, "IOBase"); + bool isFile = PyObject_IsInstance(file, IOBase_Class); + Py_DECREF(IOBase_Class); + Py_DECREF(io); + return isFile; +} +} +#endif + void PropertyFileIncluded::setPyObject(PyObject *value) { +#if PY_MAJOR_VERSION >= 3 + std::string string; + if (PyUnicode_Check(value)) { + string = PyUnicode_AsUTF8(value); + } + else if (PyBytes_Check(value)) { + string = PyBytes_AsString(value); + } + else if (isIOFile(value)){ + string = getNameFromFile(value); + } +#else std::string string; if (PyUnicode_Check(value)) { PyObject* unicode = PyUnicode_AsUTF8String(value); @@ -268,6 +315,7 @@ void PropertyFileIncluded::setPyObject(PyObject *value) PyObject* FileName = PyFile_Name(value); string = PyString_AsString(FileName); } +#endif else if (PyTuple_Check(value)) { if (PyTuple_Size(value) != 2) throw Base::TypeError("Tuple needs size of (filePath,newFileName)"); @@ -276,6 +324,17 @@ void PropertyFileIncluded::setPyObject(PyObject *value) // decoding file std::string fileStr; +#if PY_MAJOR_VERSION >= 3 + if (PyUnicode_Check(file)) { + fileStr = PyUnicode_AsUTF8(file); + } + else if (PyBytes_Check(file)) { + fileStr = PyBytes_AsString(file); + } + else if (isIOFile(value)) { + fileStr = getNameFromFile(file); + } +#else if (PyUnicode_Check(file)) { PyObject* unicode = PyUnicode_AsUTF8String(file); fileStr = PyString_AsString(unicode); @@ -288,6 +347,7 @@ void PropertyFileIncluded::setPyObject(PyObject *value) PyObject* FileName = PyFile_Name(file); fileStr = PyString_AsString(FileName); } +#endif else { std::string error = std::string("First item in tuple must be a file or string, not "); error += file->ob_type->tp_name; @@ -296,6 +356,17 @@ void PropertyFileIncluded::setPyObject(PyObject *value) // decoding name std::string nameStr; +#if PY_MAJOR_VERSION >= 3 + if (PyUnicode_Check(name)) { + nameStr = PyUnicode_AsUTF8(name); + } + else if (PyBytes_Check(name)) { + nameStr = PyBytes_AsString(name); + } + else if (isIOFile(value)) { + nameStr = getNameFromFile(name); + } +#else if (PyString_Check(name)) { nameStr = PyString_AsString(name); } @@ -303,6 +374,7 @@ void PropertyFileIncluded::setPyObject(PyObject *value) PyObject* FileName = PyFile_Name(name); nameStr = PyString_AsString(FileName); } +#endif else { std::string error = std::string("Second item in tuple must be a string, not "); error += name->ob_type->tp_name; diff --git a/src/App/PropertyGeo.cpp b/src/App/PropertyGeo.cpp index 48883789d7..1faed23468 100644 --- a/src/App/PropertyGeo.cpp +++ b/src/App/PropertyGeo.cpp @@ -115,24 +115,39 @@ void PropertyVector::setPyObject(PyObject *value) item = PyTuple_GetItem(value,0); if (PyFloat_Check(item)) cVec.x = PyFloat_AsDouble(item); +#if PY_MAJOR_VERSION < 3 else if (PyInt_Check(item)) cVec.x = (double)PyInt_AsLong(item); +#else + else if (PyLong_Check(item)) + cVec.x = (double)PyLong_AsLong(item); +#endif else throw Base::TypeError("Not allowed type used in tuple (float expected)..."); // y item = PyTuple_GetItem(value,1); if (PyFloat_Check(item)) cVec.y = PyFloat_AsDouble(item); +#if PY_MAJOR_VERSION < 3 else if (PyInt_Check(item)) cVec.y = (double)PyInt_AsLong(item); +#else + else if (PyLong_Check(item)) + cVec.y = (double)PyLong_AsLong(item); +#endif else throw Base::TypeError("Not allowed type used in tuple (float expected)..."); // z item = PyTuple_GetItem(value,2); if (PyFloat_Check(item)) cVec.z = PyFloat_AsDouble(item); +#if PY_MAJOR_VERSION < 3 else if (PyInt_Check(item)) cVec.z = (double)PyInt_AsLong(item); +#else + else if (PyLong_Check(item)) + cVec.z = (double)PyLong_AsLong(item); +#endif else throw Base::TypeError("Not allowed type used in tuple (float expected)..."); setValue( cVec ); @@ -433,8 +448,13 @@ void PropertyMatrix::setPyObject(PyObject *value) item = PyTuple_GetItem(value,x+y*4); if (PyFloat_Check(item)) cMatrix[x][y] = PyFloat_AsDouble(item); +#if PY_MAJOR_VERSION < 3 else if (PyInt_Check(item)) cMatrix[x][y] = (double)PyInt_AsLong(item); +#else + else if (PyLong_Check(item)) + cMatrix[x][y] = (double)PyLong_AsLong(item); +#endif else throw Base::TypeError("Not allowed type used in matrix tuple (a number expected)..."); } diff --git a/src/App/PropertyPythonObject.cpp b/src/App/PropertyPythonObject.cpp index 9ca6b4df58..45897980d5 100644 --- a/src/App/PropertyPythonObject.cpp +++ b/src/App/PropertyPythonObject.cpp @@ -325,10 +325,14 @@ void PropertyPythonObject::Restore(Base::XMLReader &reader) if (reader.hasAttribute("module") && reader.hasAttribute("class")) { Py::Module mod(PyImport_ImportModule(reader.getAttribute("module")),true); PyObject* cls = mod.getAttr(reader.getAttribute("class")).ptr(); +#if PY_MAJOR_VERSION >= 3 + if (PyType_Check(cls)) { +#else if (PyClass_Check(cls)) { this->object = PyInstance_NewRaw(cls, 0); } else if (PyType_Check(cls)) { +#endif this->object = PyType_GenericAlloc((PyTypeObject*)cls, 0); } else { @@ -340,7 +344,11 @@ void PropertyPythonObject::Restore(Base::XMLReader &reader) std::string nam = std::string(what[1].first, what[1].second); std::string cls = std::string(what[2].first, what[2].second); Py::Module mod(PyImport_ImportModule(nam.c_str()),true); +#if PY_MAJOR_VERSION >= 3 + this->object = PyObject_CallObject(mod.getAttr(cls).ptr(), NULL); +#else this->object = PyInstance_NewRaw(mod.getAttr(cls).ptr(), 0); +#endif load_pickle = true; buffer = std::string(what[2].second, end); } diff --git a/src/App/PropertyStandard.cpp b/src/App/PropertyStandard.cpp index 57ca2af33d..1c3c3af7db 100644 --- a/src/App/PropertyStandard.cpp +++ b/src/App/PropertyStandard.cpp @@ -94,9 +94,15 @@ PyObject *PropertyInteger::getPyObject(void) void PropertyInteger::setPyObject(PyObject *value) { +#if PY_MAJOR_VERSION < 3 if (PyInt_Check(value)) { aboutToSetValue(); _lValue = PyInt_AsLong(value); +#else + if (PyLong_Check(value)) { + aboutToSetValue(); + _lValue = PyLong_AsLong(value); +#endif hasSetValue(); } else { @@ -221,12 +227,16 @@ void PropertyPath::setPyObject(PyObject *value) { std::string path; if (PyUnicode_Check(value)) { +#if PY_MAJOR_VERSION >= 3 + path = PyUnicode_AsUTF8(value); +#else PyObject* unicode = PyUnicode_AsUTF8String(value); path = PyString_AsString(unicode); Py_DECREF(unicode); } else if (PyString_Check(value)) { path = PyString_AsString(value); +#endif } else { std::string error = std::string("type must be str or unicode, not "); @@ -419,15 +429,48 @@ PyObject * PropertyEnumeration::getPyObject(void) } void PropertyEnumeration::setPyObject(PyObject *value) -{ +{ +#if PY_MAJOR_VERSION < 3 if (PyInt_Check(value)) { long val = PyInt_AsLong(value); +#else + if (PyLong_Check(value)) { + long val = PyLong_AsLong(value); +#endif if (_enum.isValid()) { aboutToSetValue(); _enum.setValue(val, true); hasSetValue(); } } + else if (PyUnicode_Check(value)) { +#if PY_MAJOR_VERSION >= 3 + const char* str = PyUnicode_AsUTF8 (value); + if (_enum.contains(str)) { + aboutToSetValue(); + _enum.setValue(PyUnicode_AsUTF8 (value)); + hasSetValue(); + } + else { + std::stringstream out; + out << "'" << str << "' is not part of the enumeration"; + throw Base::ValueError(out.str()); + } +#else + PyObject* unicode = PyUnicode_AsUTF8String(value); + const char* str = PyString_AsString (unicode); + if (_enum.contains(str)) { + aboutToSetValue(); + _enum.setValue(PyString_AsString (unicode)); + hasSetValue(); + } + else { + std::stringstream out; + out << "'" << str << "' is not part of the enumeration"; + throw Base::ValueError(out.str()); + } + Py_DECREF(unicode); + } else if (PyString_Check(value)) { const char* str = PyString_AsString (value); if (_enum.contains(str)) { @@ -440,11 +483,16 @@ void PropertyEnumeration::setPyObject(PyObject *value) out << "'" << str << "' is not part of the enumeration"; throw Base::ValueError(out.str()); } +#endif } else if (PyUnicode_Check(value)) { +#if PY_MAJOR_VERSION >=3 + std::string str = PyUnicode_AsUTF8(value); +#else PyObject* unicode = PyUnicode_AsUTF8String(value); std::string str = PyString_AsString(unicode); Py_DECREF(unicode); +#endif if (_enum.contains(str.c_str())) { aboutToSetValue(); _enum.setValue(str); @@ -464,20 +512,25 @@ void PropertyEnumeration::setPyObject(PyObject *value) for (Py_ssize_t i = 0; i < nSize; ++i) { PyObject *item = PySequence_GetItem(value, i); - if (PyString_Check(item)) { - values[i] = PyString_AsString(item); - } - else if (PyUnicode_Check(item)) { + if (PyUnicode_Check(item)) { +#if PY_MAJOR_VERSION >= 3 + values[i] = PyUnicode_AsUTF8(item); +#else PyObject* unicode = PyUnicode_AsUTF8String(item); values[i] = PyString_AsString(unicode); Py_DECREF(unicode); +#endif } +#if PY_MAJOR_VERSION < 3 + if (PyString_Check(item)) { + values[i] = PyString_AsString(item); + } +#endif else { std::string error = std::string("type in list must be str or unicode, not "); throw Base::TypeError(error + item->ob_type->tp_name); } } - _enum.setEnums(values); setValue((long)0); } @@ -556,9 +609,14 @@ const PropertyIntegerConstraint::Constraints* PropertyIntegerConstraint::getCon } void PropertyIntegerConstraint::setPyObject(PyObject *value) -{ +{ +#if PY_MAJOR_VERSION < 3 if (PyInt_Check(value)) { long temp = PyInt_AsLong(value); +#else + if (PyLong_Check(value)) { + long temp = PyLong_AsLong(value); +#endif if (_ConstStruct) { if (temp > _ConstStruct->UpperBound) temp = _ConstStruct->UpperBound; @@ -575,8 +633,13 @@ void PropertyIntegerConstraint::setPyObject(PyObject *value) for (int i=0; i<4; i++) { PyObject* item; item = PyTuple_GetItem(value,i); +#if PY_MAJOR_VERSION < 3 if (PyInt_Check(item)) values[i] = PyInt_AsLong(item); +#else + if (PyLong_Check(item)) + values[i] = PyLong_AsLong(item); +#endif else throw Base::TypeError("Type in tuple must be int"); } @@ -682,7 +745,11 @@ PyObject *PropertyIntegerList::getPyObject(void) { PyObject* list = PyList_New(getSize()); for(int i = 0;iob_type->tp_name; throw Base::TypeError(error); } values[i] = PyInt_AsLong(item); +#else + if (!PyLong_Check(item)) { + std::string error = std::string("type in list must be int, not "); + error += item->ob_type->tp_name; + throw Base::TypeError(error); + } + values[i] = PyLong_AsLong(item); +#endif } setValues(values); } +#if PY_MAJOR_VERSION < 3 else if (PyInt_Check(value)) { setValue(PyInt_AsLong(value)); +#else + else if (PyLong_Check(value)) { + setValue(PyLong_AsLong(value)); +#endif } else { std::string error = std::string("type must be int or a sequence of int, not "); @@ -810,7 +891,11 @@ PyObject *PropertyIntegerSet::getPyObject(void) { PyObject* set = PySet_New(NULL); for(std::set::const_iterator it=_lValueSet.begin();it!=_lValueSet.end();++it) +#if PY_MAJOR_VERSION < 3 PySet_Add(set,PyInt_FromLong(*it)); +#else + PySet_Add(set,PyLong_FromLong(*it)); +#endif return set; } @@ -823,18 +908,32 @@ void PropertyIntegerSet::setPyObject(PyObject *value) for (Py_ssize_t i=0; iob_type->tp_name; throw Base::TypeError(error); } values.insert(PyInt_AsLong(item)); +#else + if (!PyLong_Check(item)) { + std::string error = std::string("type in list must be int, not "); + error += item->ob_type->tp_name; + throw Base::TypeError(error); + } + values.insert(PyLong_AsLong(item)); +#endif } setValues(values); } +#if PY_MAJOR_VERSION < 3 else if (PyInt_Check(value)) { setValue(PyInt_AsLong(value)); +#else + else if (PyLong_Check(value)) { + setValue(PyLong_AsLong(value)); +#endif } else { std::string error = std::string("type must be int or list of int, not "); @@ -941,9 +1040,15 @@ void PropertyFloat::setPyObject(PyObject *value) _dValue = PyFloat_AsDouble(value); hasSetValue(); } +#if PY_MAJOR_VERSION < 3 else if(PyInt_Check(value)) { aboutToSetValue(); _dValue = PyInt_AsLong(value); +#else + else if(PyLong_Check(value)) { + aboutToSetValue(); + _dValue = PyLong_AsLong(value); +#endif hasSetValue(); } else { @@ -1045,8 +1150,13 @@ void PropertyFloatConstraint::setPyObject(PyObject *value) _dValue = temp; hasSetValue(); } +#if PY_MAJOR_VERSION < 3 else if (PyInt_Check(value)) { double temp = (double)PyInt_AsLong(value); +#else + else if (PyLong_Check(value)) { + double temp = (double)PyLong_AsLong(value); +#endif if (_ConstStruct) { if (temp > _ConstStruct->UpperBound) temp = _ConstStruct->UpperBound; @@ -1065,8 +1175,13 @@ void PropertyFloatConstraint::setPyObject(PyObject *value) item = PyTuple_GetItem(value,i); if (PyFloat_Check(item)) values[i] = PyFloat_AsDouble(item); +#if PY_MAJOR_VERSION < 3 else if (PyInt_Check(item)) values[i] = PyInt_AsLong(item); +#else + else if (PyLong_Check(item)) + values[i] = PyLong_AsLong(item); +#endif else throw Base::TypeError("Type in tuple must be float or int"); } @@ -1186,7 +1301,7 @@ void PropertyFloatList::setPyObject(PyObject *value) PyObject* item = PyList_GetItem(value, i); if (PyFloat_Check(item)) { values[i] = PyFloat_AsDouble(item); -#if PYTHON_VERSION_MAJOR >= 3 +#if PY_MAJOR_VERSION >= 3 } else if (PyLong_Check(item)) { values[i] = static_cast(PyLong_AsLong(item)); #else @@ -1346,12 +1461,16 @@ void PropertyString::setPyObject(PyObject *value) { std::string string; if (PyUnicode_Check(value)) { +#if PY_MAJOR_VERSION >= 3 + string = PyUnicode_AsUTF8(value); +#else PyObject* unicode = PyUnicode_AsUTF8String(value); string = PyString_AsString(unicode); Py_DECREF(unicode); } else if (PyString_Check(value)) { string = PyString_AsString(value); +#endif } else { std::string error = std::string("type must be str or unicode, not "); @@ -1459,18 +1578,31 @@ const Base::Uuid& PropertyUUID::getValue(void) const PyObject *PropertyUUID::getPyObject(void) { +#if PY_MAJOR_VERSION >= 3 + PyObject *p = PyUnicode_FromString(_uuid.getValue().c_str()); +#else PyObject *p = PyString_FromString(_uuid.getValue().c_str()); +#endif return p; } void PropertyUUID::setPyObject(PyObject *value) { std::string string; - if (PyString_Check(value)) { + if (PyUnicode_Check(value)) { +#if PY_MAJOR_VERSION >= 3 + string = PyUnicode_AsUTF8(value); +#else + PyObject* unicode = PyUnicode_AsUTF8String(value); + string = PyString_AsString(unicode); + Py_DECREF(unicode); + } + else if (PyString_Check(value)) { string = PyString_AsString(value); +#endif } else { - std::string error = std::string("type must be a str, not "); + std::string error = std::string("type must be unicode or str, not "); error += value->ob_type->tp_name; throw Base::TypeError(error); } @@ -1604,9 +1736,15 @@ PyObject *PropertyStringList::getPyObject(void) void PropertyStringList::setPyObject(PyObject *value) { +#if PY_MAJOR_VERSION >=3 + if (PyBytes_Check(value)) { + setValue(PyBytes_AsString(value)); + } +#else if (PyString_Check(value)) { setValue(PyString_AsString(value)); } +#endif else if (PySequence_Check(value)) { Py_ssize_t nSize = PySequence_Size(value); std::vector values; @@ -1615,12 +1753,16 @@ void PropertyStringList::setPyObject(PyObject *value) for (Py_ssize_t i=0; i= 3 + values[i] = PyUnicode_AsUTF8(item); +#else PyObject* unicode = PyUnicode_AsUTF8String(item); values[i] = PyString_AsString(unicode); Py_DECREF(unicode); } else if (PyString_Check(item)) { values[i] = PyString_AsString(item); +#endif } else { std::string error = std::string("type in list must be str or unicode, not "); @@ -1631,8 +1773,18 @@ void PropertyStringList::setPyObject(PyObject *value) setValues(values); } + else if (PyUnicode_Check(value)) { +#if PY_MAJOR_VERSION >= 3 + setValue(PyUnicode_AsUTF8(value)); + } +#else + PyObject* unicode = PyUnicode_AsUTF8String(value); + setValue(PyString_AsString(unicode)); + Py_DECREF(unicode); + } +#endif else { - std::string error = std::string("type must be str or list of str, not "); + std::string error = std::string("type must be str or unicode or list of str or list of unicodes, not "); error += value->ob_type->tp_name; throw Base::TypeError(error); } @@ -1776,11 +1928,20 @@ void PropertyMap::setPyObject(PyObject *value) // check on the key: std::string keyStr; PyObject* key = PyList_GetItem(keyList, i); + if (PyUnicode_Check(key)) { +#if PY_MAJOR_VERSION >= 3 + keyStr = PyUnicode_AsUTF8(key); +#else + PyObject* unicode = PyUnicode_AsUTF8String(key); + keyStr = PyString_AsString(unicode); + Py_DECREF(unicode); + } if (PyString_Check(key)) { keyStr = PyString_AsString(key); +#endif } else { - std::string error = std::string("type of the key need to be a string, not"); + std::string error = std::string("type of the key need to be unicode or string, not"); error += key->ob_type->tp_name; throw Base::TypeError(error); } @@ -1788,12 +1949,16 @@ void PropertyMap::setPyObject(PyObject *value) // check on the item: PyObject* item = PyList_GetItem(itemList, i); if (PyUnicode_Check(item)) { +#if PY_MAJOR_VERSION >= 3 + values[keyStr] = PyUnicode_AsUTF8(item); +#else PyObject* unicode = PyUnicode_AsUTF8String(item); values[keyStr] = PyString_AsString(unicode); Py_DECREF(unicode); } else if (PyString_Check(item)) { values[keyStr] = PyString_AsString(item); +#endif } else { std::string error = std::string("type in list must be string or unicode, not "); @@ -1912,8 +2077,13 @@ void PropertyBool::setPyObject(PyObject *value) { if (PyBool_Check(value)) setValue(PyObject_IsTrue(value)!=0); +#if PY_MAJOR_VERSION < 3 else if(PyInt_Check(value)) setValue(PyInt_AsLong(value)!=0); +#else + else if(PyLong_Check(value)) + setValue(PyLong_AsLong(value)!=0); +#endif else { std::string error = std::string("type must be bool, not "); error += value->ob_type->tp_name; @@ -2052,8 +2222,20 @@ PyObject *PropertyBoolList::getPyObject(void) void PropertyBoolList::setPyObject(PyObject *value) { // string is also a sequence and must be be treated differently + std::string str; + if (PyUnicode_Check(value)) { +#if PY_MAJOR_VERSION >= 3 + str = PyUnicode_AsUTF8(value); +#else + PyObject* unicode = PyUnicode_AsUTF8String(value); + str = PyString_AsString(unicode); + Py_DECREF(unicode); + boost::dynamic_bitset<> values(str); + setValues(values); + } if (PyString_Check(value)) { - std::string str = PyString_AsString(value); + str = PyString_AsString(value); +#endif boost::dynamic_bitset<> values(str); setValues(values); } @@ -2066,8 +2248,13 @@ void PropertyBoolList::setPyObject(PyObject *value) if (PyBool_Check(item)) { values[i] = (PyObject_IsTrue(item) ? true : false); } +#if PY_MAJOR_VERSION < 3 else if (PyInt_Check(item)) { values[i] = (PyInt_AsLong(item) ? true : false); +#else + else if (PyLong_Check(item)) { + values[i] = (PyLong_AsLong(item) ? true : false); +#endif } else { std::string error = std::string("type in list must be bool or int, not "); @@ -2081,8 +2268,13 @@ void PropertyBoolList::setPyObject(PyObject *value) else if (PyBool_Check(value)) { setValue(PyObject_IsTrue(value) ? true : false); } +#if PY_MAJOR_VERSION < 3 else if (PyInt_Check(value)) { setValue(PyInt_AsLong(value) ? true : false); +#else + else if (PyLong_Check(value)) { + setValue(PyLong_AsLong(value) ? true : false); +#endif } else { std::string error = std::string("type must be bool or a sequence of bool, not "); diff --git a/src/App/PropertyUnits.cpp b/src/App/PropertyUnits.cpp index 12243db655..f757349d9d 100644 --- a/src/App/PropertyUnits.cpp +++ b/src/App/PropertyUnits.cpp @@ -75,19 +75,29 @@ Base::Quantity PropertyQuantity::createQuantityFromPy(PyObject *value) { Base::Quantity quant; - if (PyString_Check(value)) - quant = Quantity::parse(QString::fromLatin1(PyString_AsString(value))); - else if (PyUnicode_Check(value)){ + if (PyUnicode_Check(value)){ +#if PY_MAJOR_VERSION >= 3 + quant = Quantity::parse(QString::fromUtf8(PyUnicode_AsUTF8(value))); + } +#else PyObject* unicode = PyUnicode_AsUTF8String(value); std::string Str; Str = PyString_AsString(unicode); quant = Quantity::parse(QString::fromUtf8(Str.c_str())); Py_DECREF(unicode); } + else if (PyString_Check(value)) + quant = Quantity::parse(QString::fromLatin1(PyString_AsString(value))); +#endif else if (PyFloat_Check(value)) quant = Quantity(PyFloat_AsDouble(value),_Unit); +#if PY_MAJOR_VERSION < 3 else if (PyInt_Check(value)) quant = Quantity((double)PyInt_AsLong(value),_Unit); +#else + else if (PyLong_Check(value)) + quant = Quantity((double)PyLong_AsLong(value),_Unit); +#endif else if (PyObject_TypeCheck(value, &(QuantityPy::Type))) { Base::QuantityPy *pcObject = static_cast(value); quant = *(pcObject->getQuantityPtr()); From 7394ab727703856baa7542427eb28e48878354f5 Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 11 May 2017 19:47:54 +0200 Subject: [PATCH 03/10] minor fixes for pr749 --- src/App/DocumentObjectPyImp.cpp | 2 +- src/App/DocumentPyImp.cpp | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/App/DocumentObjectPyImp.cpp b/src/App/DocumentObjectPyImp.cpp index 6dda3c9d16..da62d024d2 100644 --- a/src/App/DocumentObjectPyImp.cpp +++ b/src/App/DocumentObjectPyImp.cpp @@ -285,10 +285,10 @@ PyObject* DocumentObjectPy::setExpression(PyObject * args) PyObject* unicode = PyUnicode_AsEncodedString(expr, "utf-8", 0); if (unicode) { std::string exprStr = PyString_AsString(unicode); + Py_DECREF(unicode); boost::shared_ptr shared_expr(ExpressionParser::parse(getDocumentObjectPtr(), exprStr.c_str())); getDocumentObjectPtr()->setExpression(p, shared_expr, comment); - Py_DECREF(unicode); } else { // utf-8 encoding failed diff --git a/src/App/DocumentPyImp.cpp b/src/App/DocumentPyImp.cpp index d69f4e6958..ce7bda4983 100644 --- a/src/App/DocumentPyImp.cpp +++ b/src/App/DocumentPyImp.cpp @@ -346,9 +346,12 @@ PyObject* DocumentPy::openTransaction(PyObject *args) cmd = PyString_AsString(value); } #endif - else + else { + PyErr_SetString(PyExc_TypeError, "string or unicode expected"); return NULL; - getDocumentPtr()->openTransaction(cmd.c_str()); + } + + getDocumentPtr()->openTransaction(cmd.c_str()); Py_Return; } From df8826ac3b5e5be625d34dd69774e4ac7fb0f2b7 Mon Sep 17 00:00:00 2001 From: looooo Date: Thu, 11 May 2017 13:27:24 +0200 Subject: [PATCH 04/10] py3: AddonManager: use urllib.request insted of urllib2 issue 0000995 --- src/Mod/AddonManager/AddonManager.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/Mod/AddonManager/AddonManager.py b/src/Mod/AddonManager/AddonManager.py index 9b7e722910..ca9a0bbaee 100644 --- a/src/Mod/AddonManager/AddonManager.py +++ b/src/Mod/AddonManager/AddonManager.py @@ -38,7 +38,12 @@ installed. ''' from PySide import QtCore, QtGui -import FreeCAD,urllib2,re,os,shutil +import sys, os, re, shutil +import FreeCAD +if sys.version_info.major < 3: + import urllib2 +else: + import urllib.request as urllib2 NOGIT = False # for debugging purposes, set this to True to always use http downloads @@ -304,6 +309,8 @@ class UpdateWorker(QtCore.QThread): self.progressbar_show.emit(True) u = urllib2.urlopen("https://github.com/FreeCAD/FreeCAD-addons") p = u.read() + if isinstance(p, bytes): + p = p.decode("utf-8") u.close() p = p.replace("\n"," ") p = re.findall("octicon-file-submodule(.*?)message",p) @@ -346,6 +353,8 @@ class InfoWorker(QtCore.QThread): url = repo[1] u = urllib2.urlopen(url) p = u.read() + if isinstance(p, bytes): + p = p.decode("utf-8") u.close() desc = re.findall("",p) if desc: @@ -374,6 +383,8 @@ class MacroWorker(QtCore.QThread): macropath = FreeCAD.ParamGet('User parameter:BaseApp/Preferences/Macro').GetString("MacroPath",os.path.join(FreeCAD.ConfigGet("UserAppData"),"Macro")) u = urllib2.urlopen("http://www.freecadweb.org/wiki/Macros_recipes") p = u.read() + if isinstance(p, bytes): + p = p.decode("utf-8") u.close() macros = re.findall("title=\"(Macro.*?)\"",p) macros = [mac for mac in macros if (not("translated" in mac))] @@ -414,6 +425,8 @@ class ShowWorker(QtCore.QThread): self.info_label.emit(translate("AddonsInstaller", "Retrieving info from ") + str(url)) u = urllib2.urlopen(url) p = u.read() + if isinstance(p, bytes): + p = p.decode("utf-8") u.close() desc = re.findall("",p) if desc: @@ -456,6 +469,8 @@ class ShowMacroWorker(QtCore.QThread): self.info_label.emit("Retrieving info from " + str(url)) u = urllib2.urlopen(url) p = u.read() + if isinstance(p, bytes): + p = p.decode("utf-8") u.close() code = re.findall("
(.*?)<\/pre>",p.replace("\n","--endl--"))
             if code:
@@ -559,7 +574,8 @@ class InstallWorker(QtCore.QThread):
 
     def download(self,giturl,clonedir):
         "downloads and unzip from github"
-        import StringIO,zipfile
+        import zipfile
+        import io
         bakdir = None
         if os.path.exists(clonedir):
             bakdir = clonedir+".bak"
@@ -573,7 +589,7 @@ class InstallWorker(QtCore.QThread):
             u = urllib2.urlopen(zipurl)
         except:
             return translate("AddonsInstaller", "Error: Unable to download") + " " + zipurl
-        zfile = StringIO.StringIO()
+        zfile = io.StringIO()
         zfile.write(u.read())
         zfile = zipfile.ZipFile(zfile)
         master = zfile.namelist()[0] # github will put everything in a subfolder

From 422328483e7de4383eb9d44559f57854add51ba7 Mon Sep 17 00:00:00 2001
From: Richard Crozier 
Date: Thu, 11 May 2017 11:39:59 +0100
Subject: [PATCH 05/10] AppPartPy.cpp: improved docstrings for Part.makeLine
 and Part.makePolygon

---
 src/Mod/Part/App/AppPartPy.cpp | 24 ++++++++++++++++++++++--
 1 file changed, 22 insertions(+), 2 deletions(-)

diff --git a/src/Mod/Part/App/AppPartPy.cpp b/src/Mod/Part/App/AppPartPy.cpp
index cbfa129116..f814a64744 100644
--- a/src/Mod/Part/App/AppPartPy.cpp
+++ b/src/Mod/Part/App/AppPartPy.cpp
@@ -286,10 +286,30 @@ public:
             "By default pnt=Vector(0,0,0) and dir=Vector(0,0,1)"
         );
         add_varargs_method("makeLine",&Module::makeLine,
-            "makeLine((x1,y1,z1),(x2,y2,z2)) -- Make a line of two points"
+            "makeLine(startpnt,endpnt) -- Make a line between two points\n"
+            "\n"
+            "Args:\n"
+            "    startpnt (Vector or tuple): Vector or 3 element tuple \n"
+            "        containing the x,y and z coordinates of the start point,\n"
+            "        i.e. (x1,y1,z1).\n"
+            "    endpnt (Vector or tuple): Vector or 3 element tuple \n"
+            "        containing the x,y and z coordinates of the start point,\n"
+            "        i.e. (x1,y1,z1).\n"
+            "\n"
+            "Returns:\n"
+            "    Edge: Part.Edge object\n"
         );
         add_varargs_method("makePolygon",&Module::makePolygon,
-            "makePolygon(list) -- Make a polygon of a list of points"
+            "makePolygon(pntslist) -- Make a polygon from a list of points\n"
+            "\n"
+            "Args:\n"
+            "    pntslist (list(Vector)): list of Vectors representing the \n"
+            "        points of the polygon.\n"
+            "\n"
+            "Returns:\n"
+            "    Wire: Part.Wire object. If the last point in the list is \n"
+            "        not the same as the first point, the Wire will not be \n"
+            "        closed and cannot be used to create a face.\n"
         );
         add_varargs_method("makeCircle",&Module::makeCircle,
             "makeCircle(radius,[pnt,dir,angle1,angle2]) -- Make a circle with a given radius\n"

From 3d4f8091de590385cb2dd7e52046a0cb4736d1c8 Mon Sep 17 00:00:00 2001
From: Keith Sloan 
Date: Thu, 11 May 2017 08:28:45 +0100
Subject: [PATCH 06/10] Fix for linearextrude with twist

---
 src/Mod/OpenSCAD/OpenSCADFeatures.py | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/src/Mod/OpenSCAD/OpenSCADFeatures.py b/src/Mod/OpenSCAD/OpenSCADFeatures.py
index 50e38d5559..d214282fac 100644
--- a/src/Mod/OpenSCAD/OpenSCADFeatures.py
+++ b/src/Mod/OpenSCAD/OpenSCADFeatures.py
@@ -382,7 +382,9 @@ class Twist:
                 facetransform.rotateZ(math.radians(fp.Angle.Value))
                 facetransform.move(FreeCAD.Vector(0,0,fp.Height.Value))
                 faceu.transformShape(facetransform)
-                step = 2 + int(fp.Angle.Value // 90) #resolution in z direction
+                step = 2 + abs(int(fp.Angle.Value // 90)) #resolution in z direction
+                # print abs(int(fp.Angle.Value // 90)) #resolution in z direction
+                # print step
                 zinc = fp.Height.Value/(step-1.0)
                 angleinc = math.radians(fp.Angle.Value)/(step-1.0)
                 spine = Part.makePolygon([(0,0,i*zinc) \
@@ -395,7 +397,9 @@ class Twist:
                     pipeshell=Part.BRepOffsetAPI.MakePipeShell(spine)
                     pipeshell.setSpineSupport(spine)
                     pipeshell.add(wire)
-                    pipeshell.setAuxiliarySpine(auxspine,True,False)
+                    # Was before function change
+                    # pipeshell.setAuxiliarySpine(auxspine,True,False)
+                    pipeshell.setAuxiliarySpine(auxspine,True,long(0))
                     print(pipeshell.getStatus())
                     assert(pipeshell.isReady())
                     #fp.Shape=pipeshell.makeSolid()

From c37e13b76d595e7d6eee07eff61d6230cd1fa97d Mon Sep 17 00:00:00 2001
From: Keith Sloan 
Date: Thu, 11 May 2017 14:41:27 +0100
Subject: [PATCH 07/10] Fix for linear_extrude request of null object i.e. null
 text

---
 src/Mod/OpenSCAD/importCSG.py | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/Mod/OpenSCAD/importCSG.py b/src/Mod/OpenSCAD/importCSG.py
index 06cb4d82c4..3cd6120a4f 100644
--- a/src/Mod/OpenSCAD/importCSG.py
+++ b/src/Mod/OpenSCAD/importCSG.py
@@ -653,6 +653,10 @@ def p_linear_extrude_with_twist(p):
         t = float(p[3]['twist'])
     else:
         t = 0
+    # Test if null object like from null text
+    if (len(p[6]) == 0) :
+        p[0] = []
+        return
     if (len(p[6]) > 1) :
         obj = fuse(p[6],"Linear Extrude Union")
     else :

From 736cd735ca7a8c6e7573358f2b8cae34cccbbc22 Mon Sep 17 00:00:00 2001
From: wmayer 
Date: Thu, 11 May 2017 23:34:01 +0200
Subject: [PATCH 08/10] fix possible freeze when creating sketch grid

---
 src/Mod/Part/Gui/ViewProvider2DObject.cpp | 22 ++++++++++++++--------
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/src/Mod/Part/Gui/ViewProvider2DObject.cpp b/src/Mod/Part/Gui/ViewProvider2DObject.cpp
index 5e3d0a33b1..0789cc7d8c 100644
--- a/src/Mod/Part/Gui/ViewProvider2DObject.cpp
+++ b/src/Mod/Part/Gui/ViewProvider2DObject.cpp
@@ -101,14 +101,20 @@ SoSeparator* ViewProvider2DObject::createGrid(void)
         MaY = MaxY + (MaxY-MinY)*0.2f;
     }
     else {
-        MiX = -exp(ceil(log(std::abs(MinX))));
-        MiX = std::min(MiX,(float)-exp(ceil(log(std::abs(0.1f*MaxX)))));
-        MaX = exp(ceil(log(std::abs(MaxX))));
-        MaX = std::max(MaX,(float)exp(ceil(log(std::abs(0.1f*MinX)))));
-        MiY = -exp(ceil(log(std::abs(MinY))));
-        MiY = std::min(MiY,(float)-exp(ceil(log(std::abs(0.1f*MaxY)))));
-        MaY = exp(ceil(log(std::abs(MaxY))));
-        MaY = std::max(MaY,(float)exp(ceil(log(std::abs(0.1f*MinY)))));
+        // make sure that nine of the numbers are exactly zero because log(0)
+        // is not defined
+        float xMin = std::abs(MinX) < FLT_EPSILON ? 0.01f : MinX;
+        float xMax = std::abs(MaxX) < FLT_EPSILON ? 0.01f : MaxX;
+        float yMin = std::abs(MinY) < FLT_EPSILON ? 0.01f : MinY;
+        float yMax = std::abs(MaxY) < FLT_EPSILON ? 0.01f : MaxY;
+        MiX = -exp(ceil(log(std::abs(xMin))));
+        MiX = std::min(MiX,(float)-exp(ceil(log(std::abs(0.1f*xMax)))));
+        MaX = exp(ceil(log(std::abs(xMax))));
+        MaX = std::max(MaX,(float)exp(ceil(log(std::abs(0.1f*xMin)))));
+        MiY = -exp(ceil(log(std::abs(yMin))));
+        MiY = std::min(MiY,(float)-exp(ceil(log(std::abs(0.1f*yMax)))));
+        MaY = exp(ceil(log(std::abs(yMax))));
+        MaY = std::max(MaY,(float)exp(ceil(log(std::abs(0.1f*yMin)))));
     }
     //Round the values otherwise grid is not aligned with center
     MiX = floor(MiX / Step) * Step;

From 22473ae4a8a91de3ce921bd7ea36513a9f2f5f51 Mon Sep 17 00:00:00 2001
From: wmayer 
Date: Fri, 12 May 2017 08:05:12 +0200
Subject: [PATCH 09/10] fix creation of NaN that invalidates the view frustum

---
 src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 23 ++++++++++++++-------
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp
index d4de8ccaf3..e166919ec7 100644
--- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp
+++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp
@@ -3922,14 +3922,21 @@ void ViewProviderSketch::draw(bool temp /*=false*/, bool rebuildinformationlayer
     edit->RootCrossSet->numVertices.set1Value(0,2);
     edit->RootCrossSet->numVertices.set1Value(1,2);
 
-    float MiX = -exp(ceil(log(std::abs(MinX))));
-    MiX = std::min(MiX,(float)-exp(ceil(log(std::abs(0.1f*MaxX)))));
-    float MaX = exp(ceil(log(std::abs(MaxX))));
-    MaX = std::max(MaX,(float)exp(ceil(log(std::abs(0.1f*MinX)))));
-    float MiY = -exp(ceil(log(std::abs(MinY))));
-    MiY = std::min(MiY,(float)-exp(ceil(log(std::abs(0.1f*MaxY)))));
-    float MaY = exp(ceil(log(std::abs(MaxY))));
-    MaY = std::max(MaY,(float)exp(ceil(log(std::abs(0.1f*MinY)))));
+    // make sure that nine of the numbers are exactly zero because log(0)
+    // is not defined
+    float xMin = std::abs(MinX) < FLT_EPSILON ? 0.01f : MinX;
+    float xMax = std::abs(MaxX) < FLT_EPSILON ? 0.01f : MaxX;
+    float yMin = std::abs(MinY) < FLT_EPSILON ? 0.01f : MinY;
+    float yMax = std::abs(MaxY) < FLT_EPSILON ? 0.01f : MaxY;
+
+    float MiX = -exp(ceil(log(std::abs(xMin))));
+    MiX = std::min(MiX,(float)-exp(ceil(log(std::abs(0.1f*xMax)))));
+    float MaX = exp(ceil(log(std::abs(xMax))));
+    MaX = std::max(MaX,(float)exp(ceil(log(std::abs(0.1f*xMin)))));
+    float MiY = -exp(ceil(log(std::abs(yMin))));
+    MiY = std::min(MiY,(float)-exp(ceil(log(std::abs(0.1f*yMax)))));
+    float MaY = exp(ceil(log(std::abs(yMax))));
+    MaY = std::max(MaY,(float)exp(ceil(log(std::abs(0.1f*yMin)))));
 
     edit->RootCrossCoordinate->point.set1Value(0,SbVec3f(MiX, 0.0f, zCross));
     edit->RootCrossCoordinate->point.set1Value(1,SbVec3f(MaX, 0.0f, zCross));

From 4cf4a3954e8cb3da75e4fca0d63cf7ebfa9206be Mon Sep 17 00:00:00 2001
From: "Bruce B. Lacey" 
Date: Thu, 11 May 2017 22:05:50 -0700
Subject: [PATCH 10/10] Specify Eigen3 include path on macOS

  * Orocos KDL depends upon Eigen 3.2, an older version than
    the Homebrew default, requiring that the EIGEN3_INCLUDE_DIR
    be specified to cmake providing the Eigen3 include path
---
 .travis.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.travis.yml b/.travis.yml
index 879a067d8a..b267393c62 100755
--- a/.travis.yml
+++ b/.travis.yml
@@ -184,7 +184,7 @@ before_install:
           export INSTALLED_APP_PATH="/usr/local/MacOS/FreeCAD"
        fi
 
-       export CMAKE_ARGS="${CMAKE_OPTS} -DFREECAD_USE_EXTERNAL_KDL=ON"
+       export CMAKE_ARGS="${CMAKE_OPTS} -DFREECAD_USE_EXTERNAL_KDL=ON -DEIGEN3_INCLUDE_DIR=$(brew --prefix eigen@3.2)/include/eigen3"
        ;;
 
    *)