From 64fb12719561c4ecc8454e06dcd8229924cf07a5 Mon Sep 17 00:00:00 2001 From: KmolYuan Date: Sat, 11 Dec 2021 18:49:15 +0800 Subject: [PATCH] Make solver copyable and implement its serialization. --- cython/python_solvespace/slvs.pxd | 7 +++- cython/python_solvespace/slvs.pyi | 12 ++++++ cython/python_solvespace/slvs.pyx | 68 ++++++++++++++++++++----------- cython/test/test_slvs.py | 8 +++- 4 files changed, 69 insertions(+), 26 deletions(-) diff --git a/cython/python_solvespace/slvs.pxd b/cython/python_solvespace/slvs.pxd index 05cd83df..dd14ab8a 100644 --- a/cython/python_solvespace/slvs.pxd +++ b/cython/python_solvespace/slvs.pxd @@ -247,7 +247,7 @@ cdef class SolverSystem: cdef void copy_to_sys(self) nogil cdef void copy_from_sys(self) nogil cpdef void clear(self) - cdef void failed_collecting(self) nogil + cdef void collect_failed(self) nogil cdef void free(self) cpdef void set_group(self, size_t g) cpdef int group(self) @@ -257,6 +257,11 @@ cdef class SolverSystem: cpdef object constraints(self) cpdef list failures(self) cpdef int solve(self) + + cpdef size_t param_len(self) + cpdef size_t entity_len(self) + cpdef size_t cons_len(self) + cpdef Entity create_2d_base(self) cdef Slvs_hParam new_param(self, double val) nogil cdef Slvs_hEntity eh(self) nogil diff --git a/cython/python_solvespace/slvs.pyi b/cython/python_solvespace/slvs.pyi index a8501fa1..47f40c2b 100644 --- a/cython/python_solvespace/slvs.pyi +++ b/cython/python_solvespace/slvs.pyi @@ -99,6 +99,9 @@ class SolverSystem: """Initialization method. Create a solver system.""" ... + def copy(self) -> SolverSystem: + ... + def clear(self) -> None: ... @@ -126,6 +129,15 @@ class SolverSystem: def solve(self) -> int: ... + def param_len(self) -> int: + ... + + def entity_len(self) -> int: + ... + + def cons_len(self) -> int: + ... + def create_2d_base(self) -> Entity: ... diff --git a/cython/python_solvespace/slvs.pyx b/cython/python_solvespace/slvs.pyx index 931726be..ace99962 100644 --- a/cython/python_solvespace/slvs.pyx +++ b/cython/python_solvespace/slvs.pyx @@ -279,13 +279,26 @@ cdef class SolverSystem: class. """ - def __cinit__(self): - self.g = 0 + def __cinit__(self, int g = 0, object param_list=None, object entity_list=None, object cons_list=None): + self.g = g self.sys.params = self.sys.entities = self.sys.constraints = 0 + if param_list is not None: + self.param_list = param_list + if entity_list is not None: + self.entity_list = entity_list + if cons_list is not None: + self.cons_list = cons_list def __dealloc__(self): self.free() + def __reduce__(self): + return (self.__class__, (self.g, self.param_list, self.entity_list, self.cons_list)) + + def copy(self): + """Copy the solver.""" + return SolverSystem(self.g, self.param_list, self.entity_list, self.cons_list) + cdef inline void copy_to_sys(self) nogil: """Copy data from stack into system.""" cdef int i = 0 @@ -293,13 +306,11 @@ cdef class SolverSystem: for param in self.param_list: self.sys.param[i] = param.second i += 1 - i = 0 cdef Slvs_Entity entity for entity in self.entity_list: self.sys.entity[i] = entity i += 1 - i = 0 cdef Slvs_Constraint con for con in self.cons_list: @@ -328,8 +339,9 @@ cdef class SolverSystem: self.failed_list.clear() self.free() - cdef inline void failed_collecting(self) nogil: - """Collecting the failed constraints.""" + cdef inline void collect_failed(self) nogil: + """Collect the failed constraints.""" + self.failed_list.clear() cdef int i for i in range(self.sys.faileds): self.failed_list.push_back(self.sys.failed[i]) @@ -408,11 +420,14 @@ cdef class SolverSystem: """Start the solving, return the result flag.""" # Parameters self.sys.param = PyMem_Malloc(self.param_list.size() * sizeof(Slvs_Param)) + self.sys.params = self.param_list.size() # Entities self.sys.entity = PyMem_Malloc(self.entity_list.size() * sizeof(Slvs_Entity)) + self.sys.entities = self.entity_list.size() # Constraints cdef size_t cons_size = self.cons_list.size() self.sys.constraint = PyMem_Malloc(cons_size * sizeof(Slvs_Constraint)) + self.sys.constraints = self.cons_list.size() self.sys.failed = PyMem_Malloc(cons_size * sizeof(Slvs_hConstraint)) self.sys.faileds = cons_size @@ -422,10 +437,22 @@ cdef class SolverSystem: Slvs_Solve(&self.sys, self.g) # Failed constraints and free memory. self.copy_from_sys() - self.failed_collecting() + self.collect_failed() self.free() return self.sys.result + cpdef size_t param_len(self): + """The length of parameter list.""" + return self.param_list.size() + + cpdef size_t entity_len(self): + """The length of parameter list.""" + return self.entity_list.size() + + cpdef size_t cons_len(self): + """The length of parameter list.""" + return self.cons_list.size() + cpdef Entity create_2d_base(self): """Create a 2D system on current group, return the handle of work plane. @@ -437,15 +464,13 @@ cdef class SolverSystem: cdef inline Slvs_hParam new_param(self, double val) nogil: """Add a parameter.""" - self.sys.params += 1 - cdef Slvs_hParam h = self.sys.params + cdef Slvs_hParam h = self.param_list.size() + 1 self.param_list[h] = Slvs_MakeParam(h, self.g, val) return h cdef inline Slvs_hEntity eh(self) nogil: """Return new entity handle.""" - self.sys.entities += 1 - return self.sys.entities + return self.entity_list.size() + 1 cpdef Entity add_point_2d(self, double u, double v, Entity wp): """Add a 2D point to specific work plane (`wp`) then return the handle. @@ -458,10 +483,8 @@ cdef class SolverSystem: cdef Slvs_hParam u_p = self.new_param(u) cdef Slvs_hParam v_p = self.new_param(v) - cdef Slvs_Entity e = Slvs_MakePoint2d(self.eh(), self.g, wp.h, u_p, v_p) - self.entity_list.push_back(e) - - return Entity.create(&e, 2) + self.entity_list.push_back(Slvs_MakePoint2d(self.eh(), self.g, wp.h, u_p, v_p)) + return Entity.create(&self.entity_list.back(), 2) cpdef Entity add_point_3d(self, double x, double y, double z): """Add a 3D point then return the handle. @@ -471,10 +494,8 @@ cdef class SolverSystem: cdef Slvs_hParam x_p = self.new_param(x) cdef Slvs_hParam y_p = self.new_param(y) cdef Slvs_hParam z_p = self.new_param(z) - cdef Slvs_Entity e = Slvs_MakePoint3d(self.eh(), self.g, x_p, y_p, z_p) - self.entity_list.push_back(e) - - return Entity.create(&e, 3) + self.entity_list.push_back(Slvs_MakePoint3d(self.eh(), self.g, x_p, y_p, z_p)) + return Entity.create(&self.entity_list.back(), 3) cpdef Entity add_normal_2d(self, Entity wp): """Add a 2D normal orthogonal to specific work plane (`wp`) @@ -482,9 +503,9 @@ cdef class SolverSystem: """ if wp is None or not wp.is_work_plane(): raise TypeError(f"{wp} is not a work plane") - cdef Slvs_Entity e = Slvs_MakeNormal2d(self.eh(), self.g, wp.h) - self.entity_list.push_back(e) - return Entity.create(&e, 0) + + self.entity_list.push_back(Slvs_MakeNormal2d(self.eh(), self.g, wp.h)) + return Entity.create(&self.entity_list.back(), 0) cpdef Entity add_normal_3d(self, double qw, double qx, double qy, double qz): """Add a 3D normal from quaternion then return the handle. @@ -651,9 +672,8 @@ cdef class SolverSystem: if e is None: raise TypeError(f"{e} is not a entity") - self.sys.constraints += 1 cdef Slvs_Constraint c - c.h = self.sys.constraints + c.h = self.cons_list.size() + 1 c.group = self.g c.type = c_type c.wrkpl = wp.h diff --git a/cython/test/test_slvs.py b/cython/test/test_slvs.py index a491db5d..3fd910a2 100644 --- a/cython/test/test_slvs.py +++ b/cython/test/test_slvs.py @@ -34,12 +34,18 @@ class CoreTest(TestCase): sys.distance(p1, p4, 70, wp) line1 = sys.add_line_2d(p0, p3, wp) sys.angle(line0, line1, 45, wp) - result_flag = sys.solve() self.assertEqual(result_flag, ResultFlag.OKAY) x, y = sys.params(p2.params) self.assertAlmostEqual(39.54852, x, 4) self.assertAlmostEqual(61.91009, y, 4) + # Solver copy test + sys_new = sys.copy() + result_flag = sys_new.solve() + self.assertEqual(result_flag, ResultFlag.OKAY) + x, y = sys_new.params(p2.params) + self.assertAlmostEqual(39.54852, x, 4) + self.assertAlmostEqual(61.91009, y, 4) def test_involute(self): """Involute example."""