constraint.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. /*-----------------------------------------------------------------------------
  2. | Copyright (c) 2013-2017, Nucleic Development Team.
  3. |
  4. | Distributed under the terms of the Modified BSD License.
  5. |
  6. | The full license is in the file COPYING.txt, distributed with this software.
  7. |----------------------------------------------------------------------------*/
  8. #include <algorithm>
  9. #include <sstream>
  10. #include <Python.h>
  11. #include <kiwi/kiwi.h>
  12. #include "pythonhelpers.h"
  13. #include "types.h"
  14. #include "util.h"
  15. using namespace PythonHelpers;
  16. static PyObject*
  17. Constraint_new( PyTypeObject* type, PyObject* args, PyObject* kwargs )
  18. {
  19. static const char *kwlist[] = { "expression", "op", "strength", 0 };
  20. PyObject* pyexpr;
  21. PyObject* pyop;
  22. PyObject* pystrength = 0;
  23. if( !PyArg_ParseTupleAndKeywords(
  24. args, kwargs, "OO|O:__new__", const_cast<char**>( kwlist ),
  25. &pyexpr, &pyop, &pystrength ) )
  26. return 0;
  27. if( !Expression::TypeCheck( pyexpr ) )
  28. return py_expected_type_fail( pyexpr, "Expression" );
  29. kiwi::RelationalOperator op;
  30. if( !convert_to_relational_op( pyop, op ) )
  31. return 0;
  32. double strength = kiwi::strength::required;
  33. if( pystrength && !convert_to_strength( pystrength, strength ) )
  34. return 0;
  35. PyObjectPtr pycn( PyType_GenericNew( type, args, kwargs ) );
  36. if( !pycn )
  37. return 0;
  38. Constraint* cn = reinterpret_cast<Constraint*>( pycn.get() );
  39. cn->expression = reduce_expression( pyexpr );
  40. if( !cn->expression )
  41. return 0;
  42. kiwi::Expression expr( convert_to_kiwi_expression( cn->expression ) );
  43. new( &cn->constraint ) kiwi::Constraint( expr, op, strength );
  44. return pycn.release();
  45. }
  46. static void
  47. Constraint_clear( Constraint* self )
  48. {
  49. Py_CLEAR( self->expression );
  50. }
  51. static int
  52. Constraint_traverse( Constraint* self, visitproc visit, void* arg )
  53. {
  54. Py_VISIT( self->expression );
  55. return 0;
  56. }
  57. static void
  58. Constraint_dealloc( Constraint* self )
  59. {
  60. PyObject_GC_UnTrack( self );
  61. Constraint_clear( self );
  62. self->constraint.~Constraint();
  63. Py_TYPE( self )->tp_free( pyobject_cast( self ) );
  64. }
  65. static PyObject*
  66. Constraint_repr( Constraint* self )
  67. {
  68. std::stringstream stream;
  69. Expression* expr = reinterpret_cast<Expression*>( self->expression );
  70. Py_ssize_t size = PyTuple_GET_SIZE( expr->terms );
  71. for( Py_ssize_t i = 0; i < size; ++i )
  72. {
  73. PyObject* item = PyTuple_GET_ITEM( expr->terms, i );
  74. Term* term = reinterpret_cast<Term*>( item );
  75. stream << term->coefficient << " * ";
  76. stream << reinterpret_cast<Variable*>( term->variable )->variable.name();
  77. stream << " + ";
  78. }
  79. stream << expr->constant;
  80. switch( self->constraint.op() )
  81. {
  82. case kiwi::OP_EQ:
  83. stream << " == 0";
  84. break;
  85. case kiwi::OP_LE:
  86. stream << " <= 0";
  87. break;
  88. case kiwi::OP_GE:
  89. stream << " >= 0";
  90. break;
  91. }
  92. stream << " | strength = " << self->constraint.strength();
  93. return FROM_STRING( stream.str().c_str() );
  94. }
  95. static PyObject*
  96. Constraint_expression( Constraint* self )
  97. {
  98. return newref( self->expression );
  99. }
  100. static PyObject*
  101. Constraint_op( Constraint* self )
  102. {
  103. PyObject* res = 0;
  104. switch( self->constraint.op() )
  105. {
  106. case kiwi::OP_EQ:
  107. res = FROM_STRING( "==" );
  108. break;
  109. case kiwi::OP_LE:
  110. res = FROM_STRING( "<=" );
  111. break;
  112. case kiwi::OP_GE:
  113. res = FROM_STRING( ">=" );
  114. break;
  115. }
  116. return res;
  117. }
  118. static PyObject*
  119. Constraint_strength( Constraint* self )
  120. {
  121. return PyFloat_FromDouble( self->constraint.strength() );
  122. }
  123. static PyObject*
  124. Constraint_or( PyObject* pyoldcn, PyObject* value )
  125. {
  126. if( !Constraint::TypeCheck( pyoldcn ) )
  127. std::swap( pyoldcn, value );
  128. double strength;
  129. if( !convert_to_strength( value, strength ) )
  130. return 0;
  131. PyObject* pynewcn = PyType_GenericNew( &Constraint_Type, 0, 0 );
  132. if( !pynewcn )
  133. return 0;
  134. Constraint* oldcn = reinterpret_cast<Constraint*>( pyoldcn );
  135. Constraint* newcn = reinterpret_cast<Constraint*>( pynewcn );
  136. newcn->expression = newref( oldcn->expression );
  137. new( &newcn->constraint ) kiwi::Constraint( oldcn->constraint, strength );
  138. return pynewcn;
  139. }
  140. static PyMethodDef
  141. Constraint_methods[] = {
  142. { "expression", ( PyCFunction )Constraint_expression, METH_NOARGS,
  143. "Get the expression object for the constraint." },
  144. { "op", ( PyCFunction )Constraint_op, METH_NOARGS,
  145. "Get the relational operator for the constraint." },
  146. { "strength", ( PyCFunction )Constraint_strength, METH_NOARGS,
  147. "Get the strength for the constraint." },
  148. { 0 } // sentinel
  149. };
  150. static PyNumberMethods
  151. Constraint_as_number = {
  152. 0, /* nb_add */
  153. 0, /* nb_subtract */
  154. 0, /* nb_multiply */
  155. #if PY_MAJOR_VERSION < 3
  156. 0, /* nb_divide */
  157. #endif
  158. 0, /* nb_remainder */
  159. 0, /* nb_divmod */
  160. 0, /* nb_power */
  161. 0, /* nb_negative */
  162. 0, /* nb_positive */
  163. 0, /* nb_absolute */
  164. #if PY_MAJOR_VERSION >= 3
  165. 0, /* nb_bool */
  166. #else
  167. 0, /* nb_nonzero */
  168. #endif
  169. 0, /* nb_invert */
  170. 0, /* nb_lshift */
  171. 0, /* nb_rshift */
  172. 0, /* nb_and */
  173. 0, /* nb_xor */
  174. (binaryfunc)Constraint_or, /* nb_or */
  175. #if PY_MAJOR_VERSION < 3
  176. 0, /* nb_coerce */
  177. #endif
  178. 0, /* nb_int */
  179. 0, /* nb_long */
  180. 0, /* nb_float */
  181. #if PY_MAJOR_VERSION < 3
  182. 0, /* nb_oct */
  183. 0, /* nb_hex */
  184. #endif
  185. 0, /* nb_inplace_add */
  186. 0, /* nb_inplace_subtract */
  187. 0, /* nb_inplace_multiply */
  188. #if PY_MAJOR_VERSION < 3
  189. 0, /* nb_inplace_divide */
  190. #endif
  191. 0, /* nb_inplace_remainder */
  192. 0, /* nb_inplace_power */
  193. 0, /* nb_inplace_lshift */
  194. 0, /* nb_inplace_rshift */
  195. 0, /* nb_inplace_and */
  196. 0, /* nb_inplace_xor */
  197. 0, /* nb_inplace_or */
  198. (binaryfunc)0, /* nb_floor_divide */
  199. (binaryfunc)0, /* nb_true_divide */
  200. 0, /* nb_inplace_floor_divide */
  201. 0, /* nb_inplace_true_divide */
  202. #if PY_VERSION_HEX >= 0x02050000
  203. (unaryfunc)0, /* nb_index */
  204. #endif
  205. #if PY_VERSION_HEX >= 0x03050000
  206. (binaryfunc)0, /* nb_matrix_multiply */
  207. (binaryfunc)0, /* nb_inplace_matrix_multiply */
  208. #endif
  209. };
  210. PyTypeObject Constraint_Type = {
  211. PyVarObject_HEAD_INIT( &PyType_Type, 0 )
  212. "kiwisolver.Constraint", /* tp_name */
  213. sizeof( Constraint ), /* tp_basicsize */
  214. 0, /* tp_itemsize */
  215. (destructor)Constraint_dealloc, /* tp_dealloc */
  216. (printfunc)0, /* tp_print */
  217. (getattrfunc)0, /* tp_getattr */
  218. (setattrfunc)0, /* tp_setattr */
  219. #if PY_VERSION_HEX >= 0x03050000
  220. ( PyAsyncMethods* )0, /* tp_as_async */
  221. #elif PY_VERSION_HEX >= 0x03000000
  222. ( void* ) 0, /* tp_reserved */
  223. #else
  224. ( cmpfunc )0, /* tp_compare */
  225. #endif
  226. (reprfunc)Constraint_repr, /* tp_repr */
  227. (PyNumberMethods*)&Constraint_as_number,/* tp_as_number */
  228. (PySequenceMethods*)0, /* tp_as_sequence */
  229. (PyMappingMethods*)0, /* tp_as_mapping */
  230. (hashfunc)0, /* tp_hash */
  231. (ternaryfunc)0, /* tp_call */
  232. (reprfunc)0, /* tp_str */
  233. (getattrofunc)0, /* tp_getattro */
  234. (setattrofunc)0, /* tp_setattro */
  235. (PyBufferProcs*)0, /* tp_as_buffer */
  236. #if PY_MAJOR_VERSION >= 3
  237. Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE, /* tp_flags */
  238. #else
  239. Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, /* tp_flags */
  240. #endif
  241. 0, /* Documentation string */
  242. (traverseproc)Constraint_traverse, /* tp_traverse */
  243. (inquiry)Constraint_clear, /* tp_clear */
  244. (richcmpfunc)0, /* tp_richcompare */
  245. 0, /* tp_weaklistoffset */
  246. (getiterfunc)0, /* tp_iter */
  247. (iternextfunc)0, /* tp_iternext */
  248. (struct PyMethodDef*)Constraint_methods,/* tp_methods */
  249. (struct PyMemberDef*)0, /* tp_members */
  250. 0, /* tp_getset */
  251. 0, /* tp_base */
  252. 0, /* tp_dict */
  253. (descrgetfunc)0, /* tp_descr_get */
  254. (descrsetfunc)0, /* tp_descr_set */
  255. 0, /* tp_dictoffset */
  256. (initproc)0, /* tp_init */
  257. (allocfunc)PyType_GenericAlloc, /* tp_alloc */
  258. (newfunc)Constraint_new, /* tp_new */
  259. (freefunc)PyObject_GC_Del, /* tp_free */
  260. (inquiry)0, /* tp_is_gc */
  261. 0, /* tp_bases */
  262. 0, /* tp_mro */
  263. 0, /* tp_cache */
  264. 0, /* tp_subclasses */
  265. 0, /* tp_weaklist */
  266. (destructor)0 /* tp_del */
  267. };
  268. int import_constraint()
  269. {
  270. return PyType_Ready( &Constraint_Type );
  271. }