Base: misc patches

Convenience macros/function (in Interpreter.h)

* FC_PY_GetObject/Callable(), look for callables in a python object,
  which will be used in future patch to improve performance in various
  python observer/features.

* pyCall(WithKeywords)(), helper function to invoke the callable

Matrix4D:

* hasScale(), check if there is any scale in the transformation. If so,
  further check if the scale is uniform or not. This will be used in
  future patch for Part::TopoShape to decide which type of transform to
  apply.

Placement:

* translate/rotate(), new convenience API

Rotation:

* isSame/multiVec(), new convenience API

Polygon2d:

* Intersect(), GetCenter(), new convenience API.

FlagToggler:

* New class for exception safe flag toggling, similar to StateLocker
  but with template (actually, FlagToggler is added earlier by me).

BitsetLocker:

* New class for exception manipulation of a std::bitset variable.
This commit is contained in:
Zheng, Lei
2019-07-06 17:10:17 +08:00
committed by wmayer
parent 59417068f5
commit 3fcbf71fb5
12 changed files with 230 additions and 2 deletions

View File

@@ -53,6 +53,40 @@
#include "Exception.h"
/** Helper macro to obtain callable from an object
*
* @param _pyobj: PyObject pointer
* @param _name: the callable string name
* @param _var: the callable variable to be assigned
*
* See FeaturePythonImp::init() for example usage
*/
#define FC_PY_GetCallable(_pyobj,_name,_var) \
do {\
_var = Py::Object();\
if(PyObject_HasAttrString(_pyobj, _name)) {\
Py::Object _obj(PyObject_GetAttrString (_pyobj, _name), true);\
if(_obj.isCallable())\
_var = _obj;\
}\
}while(0)
/** Helper macro to obtain attribute from an object
*
* @param _pyobj: PyObject pointer
* @param _name: the attribute string name
* @param _var: the attribute variable to be assigned
*
* See FeaturePythonImp::init() for example usage
*/
#define FC_PY_GetObject(_pyobj,_name,_var) \
do {\
_var = Py::Object();\
if(PyObject_HasAttrString(_pyobj, _name))\
_var = Py::asObject(PyObject_GetAttrString (_pyobj, _name));\
}while(0)
namespace Base {
using std::string;
@@ -87,6 +121,20 @@ protected:
PyObject *_exceptionType;
};
inline Py::Object pyCall(PyObject *callable, PyObject *args=0) {
PyObject *result = PyObject_CallObject(callable, args);
if(!result)
Base::PyException::ThrowException();
return Py::asObject(result);
}
inline Py::Object pyCallWithKeywords(PyObject *callable, PyObject *args, PyObject *kwds=0) {
PyObject *result = PyObject_Call(callable, args, kwds);
if(!result)
Base::PyException::ThrowException();
return Py::asObject(result);
}
/**
* The SystemExitException is thrown if the Python-internal PyExc_SystemExit exception
* was thrown.

View File

@@ -947,3 +947,26 @@ Matrix4D& Matrix4D::Hat(const Vector3d& rV)
return *this;
}
int Matrix4D::hasScale(double tol) const {
// check for uniform scaling
//
// scaling factors are the colum vector length. We use square distance and
// ignore the actual scaling signess
//
if(!tol)
tol = 1e-9;
double dx = Vector3d(dMtrx4D[0][0],dMtrx4D[1][0],dMtrx4D[2][0]).Sqr();
double dy = Vector3d(dMtrx4D[0][1],dMtrx4D[1][1],dMtrx4D[2][1]).Sqr();
if(fabs(dx-dy)>tol)
return -1;
else {
double dz = Vector3d(dMtrx4D[0][2],dMtrx4D[1][2],dMtrx4D[2][2]).Sqr();
if(fabs(dy-dz)>tol)
return -1;
}
if(fabs(dx-1.0)>tol)
return 1;
else
return 0;
}

View File

@@ -136,6 +136,8 @@ public:
/// scale for the x,y,z value
void scale (const Vector3f& rclVct);
void scale (const Vector3d& rclVct);
/// Check for scaling factor, 0: not scale, 1: uniform scale, or else -1
int hasScale(double tol=0.0) const;
/// Rotate around the X axis (in transformed space) for the given value in radians
void rotX (double fAngle);
/// Rotate around the Y axis (in transformed space) for the given value in radians

View File

@@ -34,6 +34,14 @@ Scale the matrix with the vector
</UserDocu>
</Documentation>
</Methode>
<Methode Name="hasScale">
<Documentation>
<UserDocu>
hasScale(tol=None)
Return 0 is no scale factor, 1 for uniform scaling, -1 for non-uniform scaling.
</UserDocu>
</Documentation>
</Methode>
<Methode Name="unity">
<Documentation>
<UserDocu>unity() - make this matrix to unity</UserDocu>

View File

@@ -238,6 +238,14 @@ PyObject* MatrixPy::scale(PyObject * args)
Py_Return;
}
PyObject* MatrixPy::hasScale(PyObject * args)
{
double tol=0;
if(!PyArg_ParseTuple(args, "|d", &tol))
return 0;
return Py::new_reference_to(Py::Int(getMatrixPtr()->hasScale(tol)));
}
PyObject* MatrixPy::unity(PyObject * args)
{
if (!PyArg_ParseTuple(args, "")) // convert args: Python->C

View File

@@ -44,6 +44,22 @@ Placement(Base, Axis, Angle) -- define position and rotation
</UserDocu>
</Documentation>
</Methode>
<Methode Name="translate">
<Documentation>
<UserDocu>
translate(Vector)
alias to move(), to be compatible with TopoShape.translate()
</UserDocu>
</Documentation>
</Methode>
<Methode Name="rotate">
<Documentation>
<UserDocu>
rotate(center,axis,degree) - rotate the current placement around center and axis with degree
This method is compatible with TopoShape.rotate()
</UserDocu>
</Documentation>
</Methode>
<Methode Name="multiply" Const="true">
<Documentation>
<UserDocu>

View File

@@ -33,6 +33,7 @@
#include "MatrixPy.h"
#include "RotationPy.h"
#include "VectorPy.h"
#include "Tools.h"
using namespace Base;
@@ -158,6 +159,34 @@ PyObject* PlacementPy::move(PyObject * args)
Py_Return;
}
PyObject* PlacementPy::translate(PyObject * args)
{
return move(args);
}
PyObject* PlacementPy::rotate(PyObject *args) {
PyObject *obj1, *obj2;
double angle;
if (!PyArg_ParseTuple(args, "OOd", &obj1, &obj2, &angle))
return NULL;
try {
Py::Sequence p1(obj1), p2(obj2);
Vector3d center((double)Py::Float(p1[0]),
(double)Py::Float(p1[1]),
(double)Py::Float(p1[2]));
Vector3d axis((double)Py::Float(p2[0]),
(double)Py::Float(p2[1]),
(double)Py::Float(p2[2]));
(*getPlacementPtr()) *= Placement(
Vector3d(),Rotation(axis,toRadians<double>(angle)),center);
Py_Return;
}
catch (const Py::Exception&) {
return NULL;
}
}
PyObject* PlacementPy::multiply(PyObject * args)
{
PyObject *plm;

View File

@@ -396,6 +396,18 @@ bool Rotation::isSame(const Rotation& q) const
return false;
}
bool Rotation::isSame(const Rotation& q, double tol) const
{
Vector3d v(0,0,1);
return std::fabs(multVec(v).GetAngle(q.multVec(v))) < tol;
}
Vector3d Rotation::multVec(const Vector3d & src) const {
Vector3d dst;
multVec(src,dst);
return dst;
}
void Rotation::multVec(const Vector3d & src, Vector3d & dst) const
{
double x = this->quat[0];

View File

@@ -84,8 +84,10 @@ public:
void operator = (const Rotation&);
void multVec(const Vector3d & src, Vector3d & dst) const;
Vector3d multVec(const Vector3d & src) const;
void scaleAngle(const double scaleFactor);
bool isSame(const Rotation&) const;
bool isSame(const Rotation&, double tol) const;
//@}
/** Specialty constructors */

View File

@@ -187,6 +187,33 @@ private:
// ----------------------------------------------------------------------------
template<typename Flag=bool>
struct FlagToggler {
Flag &flag;
bool toggled;
FlagToggler(Flag &_flag)
:flag(_flag),toggled(true)
{
flag = !flag;
}
FlagToggler(Flag &_flag, Flag check)
:flag(_flag),toggled(check==_flag)
{
if(toggled)
flag = !flag;
}
~FlagToggler() {
if(toggled)
flag = !flag;
}
};
// ----------------------------------------------------------------------------
template<typename Status, class Object>
class ObjectStatusLocker
{
@@ -217,6 +244,23 @@ private:
// ----------------------------------------------------------------------------
template<typename T>
class BitsetLocker
{
public:
BitsetLocker(T& flags, std::size_t flag, bool value = true)
: flags(flags), flag(flag)
{ oldValue = flags.test(flag); flags.set(flag,value); }
~BitsetLocker()
{ flags.set(flag,oldValue); }
private:
T &flags;
std::size_t flag;
bool oldValue;
};
// ----------------------------------------------------------------------------
class ConnectionBlocker {
typedef boost::signals2::connection Connection;
typedef boost::signals2::shared_connection_block ConnectionBlock;

View File

@@ -431,6 +431,37 @@ void Polygon2d::Intersect (const Polygon2d &rclPolygon, std::list<Polygon2d> &rc
rclResultPolygonList.push_back(clResultPolygon);
}
bool Polygon2d::Intersect (const Polygon2d &other) const {
if(other.GetCtVectors()<2 || GetCtVectors() < 2)
return false;
for(auto &v : _aclVct) {
if(other.Contains(v))
return true;
}
if(Contains(other[0]))
return true;
for(size_t j=1; j<other.GetCtVectors(); ++j) {
auto &v0 = other[j-1];
auto &v1 = other[j];
if(Contains(v1))
return true;
Line2d line(v0, v1);
for(size_t i=0; i<GetCtVectors(); ++i) {
Line2d line2(At(i), At((i+1)%GetCtVectors()));
Vector2d v;
if(line.IntersectAndContain(line2, v))
return true;
}
}
return false;
}
bool Polygon2d::Intersect (const Vector2d &rclV, double eps) const
{
if (_aclVct.size() < 2)

View File

@@ -89,7 +89,7 @@ public:
inline BoundBox2d (double fX1, double fY1, double fX2, double fY2);
inline bool IsValid (void);
inline bool IsEqual(const BoundBox2d&, double tolerance) const;
// operators
inline BoundBox2d& operator= (const BoundBox2d& rclBB);
inline bool operator== (const BoundBox2d& rclBB) const;
@@ -102,6 +102,11 @@ public:
// misc
bool Contains (const Vector2d &rclV) const;
inline Vector2d GetCenter() const {
return Vector2d((MinX+MaxX)/2,(MinY+MaxY)/2);
}
};
/** Line2d ********************************************/
@@ -160,6 +165,7 @@ public:
BoundBox2d CalcBoundBox (void) const;
bool Contains (const Vector2d &rclV) const;
void Intersect (const Polygon2d &rclPolygon, std::list<Polygon2d> &rclResultPolygonList) const;
bool Intersect (const Polygon2d &rclPolygon) const;
bool Intersect (const Vector2d &rclV, double eps) const;
private:
@@ -308,7 +314,6 @@ inline Vector2d& Polygon2d::At (size_t ulNdx) const
return (Vector2d&) _aclVct[ulNdx];
}
inline Line2d::Line2d (const Line2d &rclLine)
: clV1 (rclLine.clV1),
clV2 (rclLine.clV2)