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" ;; *) diff --git a/src/App/DocumentObjectPyImp.cpp b/src/App/DocumentObjectPyImp.cpp index b14d2f3fab..da62d024d2 100644 --- a/src/App/DocumentObjectPyImp.cpp +++ b/src/App/DocumentObjectPyImp.cpp @@ -267,13 +267,21 @@ 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); @@ -286,6 +294,7 @@ PyObject* DocumentObjectPy::setExpression(PyObject * args) // 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..ce7bda4983 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,6 +345,12 @@ PyObject* DocumentPy::openTransaction(PyObject *args) else if (PyString_Check(value)) { cmd = PyString_AsString(value); } +#endif + else { + PyErr_SetString(PyExc_TypeError, "string or unicode expected"); + return NULL; + } + getDocumentPtr()->openTransaction(cmd.c_str()); Py_Return; } @@ -521,9 +538,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 +609,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()); 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
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()
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 :
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"
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;
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;
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));