constraint.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /*-----------------------------------------------------------------------------
  2. | Copyright (c) 2013-2019, Nucleic Development Team.
  3. |
  4. | Distributed under the terms of the Modified BSD License.
  5. |
  6. | The full license is in the file LICENSE, distributed with this software.
  7. |----------------------------------------------------------------------------*/
  8. #include <algorithm>
  9. #include <sstream>
  10. #include <cppy/cppy.h>
  11. #include <kiwi/kiwi.h>
  12. #include "types.h"
  13. #include "util.h"
  14. namespace kiwisolver
  15. {
  16. namespace
  17. {
  18. PyObject *
  19. Constraint_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
  20. {
  21. static const char *kwlist[] = {"expression", "op", "strength", 0};
  22. PyObject *pyexpr;
  23. PyObject *pyop;
  24. PyObject *pystrength = 0;
  25. if (!PyArg_ParseTupleAndKeywords(
  26. args, kwargs, "OO|O:__new__", const_cast<char **>(kwlist),
  27. &pyexpr, &pyop, &pystrength))
  28. return 0;
  29. if (!Expression::TypeCheck(pyexpr))
  30. return cppy::type_error(pyexpr, "Expression");
  31. kiwi::RelationalOperator op;
  32. if (!convert_to_relational_op(pyop, op))
  33. return 0;
  34. double strength = kiwi::strength::required;
  35. if (pystrength && !convert_to_strength(pystrength, strength))
  36. return 0;
  37. cppy::ptr pycn(PyType_GenericNew(type, args, kwargs));
  38. if (!pycn)
  39. return 0;
  40. Constraint *cn = reinterpret_cast<Constraint *>(pycn.get());
  41. cn->expression = reduce_expression(pyexpr);
  42. if (!cn->expression)
  43. return 0;
  44. kiwi::Expression expr(convert_to_kiwi_expression(cn->expression));
  45. new (&cn->constraint) kiwi::Constraint(expr, op, strength);
  46. return pycn.release();
  47. }
  48. void Constraint_clear(Constraint *self)
  49. {
  50. Py_CLEAR(self->expression);
  51. }
  52. int Constraint_traverse(Constraint *self, visitproc visit, void *arg)
  53. {
  54. Py_VISIT(self->expression);
  55. #if PY_VERSION_HEX >= 0x03090000
  56. // This was not needed before Python 3.9 (Python issue 35810 and 40217)
  57. Py_VISIT(Py_TYPE(self));
  58. #endif
  59. return 0;
  60. }
  61. void Constraint_dealloc(Constraint *self)
  62. {
  63. PyObject_GC_UnTrack(self);
  64. Constraint_clear(self);
  65. self->constraint.~Constraint();
  66. Py_TYPE(self)->tp_free(pyobject_cast(self));
  67. }
  68. PyObject *
  69. Constraint_repr(Constraint *self)
  70. {
  71. std::stringstream stream;
  72. Expression *expr = reinterpret_cast<Expression *>(self->expression);
  73. Py_ssize_t size = PyTuple_GET_SIZE(expr->terms);
  74. for (Py_ssize_t i = 0; i < size; ++i)
  75. {
  76. PyObject *item = PyTuple_GET_ITEM(expr->terms, i);
  77. Term *term = reinterpret_cast<Term *>(item);
  78. stream << term->coefficient << " * ";
  79. stream << reinterpret_cast<Variable *>(term->variable)->variable.name();
  80. stream << " + ";
  81. }
  82. stream << expr->constant;
  83. switch (self->constraint.op())
  84. {
  85. case kiwi::OP_EQ:
  86. stream << " == 0";
  87. break;
  88. case kiwi::OP_LE:
  89. stream << " <= 0";
  90. break;
  91. case kiwi::OP_GE:
  92. stream << " >= 0";
  93. break;
  94. }
  95. stream << " | strength = " << self->constraint.strength();
  96. return PyUnicode_FromString(stream.str().c_str());
  97. }
  98. PyObject *
  99. Constraint_expression(Constraint *self)
  100. {
  101. return cppy::incref(self->expression);
  102. }
  103. PyObject *
  104. Constraint_op(Constraint *self)
  105. {
  106. PyObject *res = 0;
  107. switch (self->constraint.op())
  108. {
  109. case kiwi::OP_EQ:
  110. res = PyUnicode_FromString("==");
  111. break;
  112. case kiwi::OP_LE:
  113. res = PyUnicode_FromString("<=");
  114. break;
  115. case kiwi::OP_GE:
  116. res = PyUnicode_FromString(">=");
  117. break;
  118. }
  119. return res;
  120. }
  121. PyObject *
  122. Constraint_strength(Constraint *self)
  123. {
  124. return PyFloat_FromDouble(self->constraint.strength());
  125. }
  126. PyObject *
  127. Constraint_or(PyObject *pyoldcn, PyObject *value)
  128. {
  129. if (!Constraint::TypeCheck(pyoldcn))
  130. std::swap(pyoldcn, value);
  131. double strength;
  132. if (!convert_to_strength(value, strength))
  133. return 0;
  134. PyObject *pynewcn = PyType_GenericNew(Constraint::TypeObject, 0, 0);
  135. if (!pynewcn)
  136. return 0;
  137. Constraint *oldcn = reinterpret_cast<Constraint *>(pyoldcn);
  138. Constraint *newcn = reinterpret_cast<Constraint *>(pynewcn);
  139. newcn->expression = cppy::incref(oldcn->expression);
  140. new (&newcn->constraint) kiwi::Constraint(oldcn->constraint, strength);
  141. return pynewcn;
  142. }
  143. static PyMethodDef
  144. Constraint_methods[] = {
  145. {"expression", (PyCFunction)Constraint_expression, METH_NOARGS,
  146. "Get the expression object for the constraint."},
  147. {"op", (PyCFunction)Constraint_op, METH_NOARGS,
  148. "Get the relational operator for the constraint."},
  149. {"strength", (PyCFunction)Constraint_strength, METH_NOARGS,
  150. "Get the strength for the constraint."},
  151. {0} // sentinel
  152. };
  153. static PyType_Slot Constraint_Type_slots[] = {
  154. {Py_tp_dealloc, void_cast(Constraint_dealloc)}, /* tp_dealloc */
  155. {Py_tp_traverse, void_cast(Constraint_traverse)}, /* tp_traverse */
  156. {Py_tp_clear, void_cast(Constraint_clear)}, /* tp_clear */
  157. {Py_tp_repr, void_cast(Constraint_repr)}, /* tp_repr */
  158. {Py_tp_methods, void_cast(Constraint_methods)}, /* tp_methods */
  159. {Py_tp_new, void_cast(Constraint_new)}, /* tp_new */
  160. {Py_tp_alloc, void_cast(PyType_GenericAlloc)}, /* tp_alloc */
  161. {Py_tp_free, void_cast(PyObject_GC_Del)}, /* tp_free */
  162. {Py_nb_or, void_cast(Constraint_or)}, /* nb_or */
  163. {0, 0},
  164. };
  165. } // namespace
  166. // Initialize static variables (otherwise the compiler eliminates them)
  167. PyTypeObject *Constraint::TypeObject = NULL;
  168. PyType_Spec Constraint::TypeObject_Spec = {
  169. "kiwisolver.Constraint", /* tp_name */
  170. sizeof(Constraint), /* tp_basicsize */
  171. 0, /* tp_itemsize */
  172. Py_TPFLAGS_DEFAULT |
  173. Py_TPFLAGS_HAVE_GC |
  174. Py_TPFLAGS_BASETYPE, /* tp_flags */
  175. Constraint_Type_slots /* slots */
  176. };
  177. bool Constraint::Ready()
  178. {
  179. // The reference will be handled by the module to which we will add the type
  180. TypeObject = pytype_cast(PyType_FromSpec(&TypeObject_Spec));
  181. if (!TypeObject)
  182. {
  183. return false;
  184. }
  185. return true;
  186. }
  187. } // namespace kiwisolver