Make solver copyable and implement its serialization.

pull/493/head
KmolYuan 2021-12-11 18:49:15 +08:00
parent 3c98d4d270
commit 64fb127195
4 changed files with 69 additions and 26 deletions

View File

@ -247,7 +247,7 @@ cdef class SolverSystem:
cdef void copy_to_sys(self) nogil cdef void copy_to_sys(self) nogil
cdef void copy_from_sys(self) nogil cdef void copy_from_sys(self) nogil
cpdef void clear(self) cpdef void clear(self)
cdef void failed_collecting(self) nogil cdef void collect_failed(self) nogil
cdef void free(self) cdef void free(self)
cpdef void set_group(self, size_t g) cpdef void set_group(self, size_t g)
cpdef int group(self) cpdef int group(self)
@ -257,6 +257,11 @@ cdef class SolverSystem:
cpdef object constraints(self) cpdef object constraints(self)
cpdef list failures(self) cpdef list failures(self)
cpdef int solve(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) cpdef Entity create_2d_base(self)
cdef Slvs_hParam new_param(self, double val) nogil cdef Slvs_hParam new_param(self, double val) nogil
cdef Slvs_hEntity eh(self) nogil cdef Slvs_hEntity eh(self) nogil

View File

@ -99,6 +99,9 @@ class SolverSystem:
"""Initialization method. Create a solver system.""" """Initialization method. Create a solver system."""
... ...
def copy(self) -> SolverSystem:
...
def clear(self) -> None: def clear(self) -> None:
... ...
@ -126,6 +129,15 @@ class SolverSystem:
def solve(self) -> int: 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: def create_2d_base(self) -> Entity:
... ...

View File

@ -279,13 +279,26 @@ cdef class SolverSystem:
class. class.
""" """
def __cinit__(self): def __cinit__(self, int g = 0, object param_list=None, object entity_list=None, object cons_list=None):
self.g = 0 self.g = g
self.sys.params = self.sys.entities = self.sys.constraints = 0 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): def __dealloc__(self):
self.free() 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: cdef inline void copy_to_sys(self) nogil:
"""Copy data from stack into system.""" """Copy data from stack into system."""
cdef int i = 0 cdef int i = 0
@ -293,13 +306,11 @@ cdef class SolverSystem:
for param in self.param_list: for param in self.param_list:
self.sys.param[i] = param.second self.sys.param[i] = param.second
i += 1 i += 1
i = 0 i = 0
cdef Slvs_Entity entity cdef Slvs_Entity entity
for entity in self.entity_list: for entity in self.entity_list:
self.sys.entity[i] = entity self.sys.entity[i] = entity
i += 1 i += 1
i = 0 i = 0
cdef Slvs_Constraint con cdef Slvs_Constraint con
for con in self.cons_list: for con in self.cons_list:
@ -328,8 +339,9 @@ cdef class SolverSystem:
self.failed_list.clear() self.failed_list.clear()
self.free() self.free()
cdef inline void failed_collecting(self) nogil: cdef inline void collect_failed(self) nogil:
"""Collecting the failed constraints.""" """Collect the failed constraints."""
self.failed_list.clear()
cdef int i cdef int i
for i in range(self.sys.faileds): for i in range(self.sys.faileds):
self.failed_list.push_back(self.sys.failed[i]) self.failed_list.push_back(self.sys.failed[i])
@ -408,11 +420,14 @@ cdef class SolverSystem:
"""Start the solving, return the result flag.""" """Start the solving, return the result flag."""
# Parameters # Parameters
self.sys.param = <Slvs_Param *>PyMem_Malloc(self.param_list.size() * sizeof(Slvs_Param)) self.sys.param = <Slvs_Param *>PyMem_Malloc(self.param_list.size() * sizeof(Slvs_Param))
self.sys.params = self.param_list.size()
# Entities # Entities
self.sys.entity = <Slvs_Entity *>PyMem_Malloc(self.entity_list.size() * sizeof(Slvs_Entity)) self.sys.entity = <Slvs_Entity *>PyMem_Malloc(self.entity_list.size() * sizeof(Slvs_Entity))
self.sys.entities = self.entity_list.size()
# Constraints # Constraints
cdef size_t cons_size = self.cons_list.size() cdef size_t cons_size = self.cons_list.size()
self.sys.constraint = <Slvs_Constraint *>PyMem_Malloc(cons_size * sizeof(Slvs_Constraint)) self.sys.constraint = <Slvs_Constraint *>PyMem_Malloc(cons_size * sizeof(Slvs_Constraint))
self.sys.constraints = self.cons_list.size()
self.sys.failed = <Slvs_hConstraint *>PyMem_Malloc(cons_size * sizeof(Slvs_hConstraint)) self.sys.failed = <Slvs_hConstraint *>PyMem_Malloc(cons_size * sizeof(Slvs_hConstraint))
self.sys.faileds = cons_size self.sys.faileds = cons_size
@ -422,10 +437,22 @@ cdef class SolverSystem:
Slvs_Solve(&self.sys, self.g) Slvs_Solve(&self.sys, self.g)
# Failed constraints and free memory. # Failed constraints and free memory.
self.copy_from_sys() self.copy_from_sys()
self.failed_collecting() self.collect_failed()
self.free() self.free()
return self.sys.result 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): cpdef Entity create_2d_base(self):
"""Create a 2D system on current group, """Create a 2D system on current group,
return the handle of work plane. return the handle of work plane.
@ -437,15 +464,13 @@ cdef class SolverSystem:
cdef inline Slvs_hParam new_param(self, double val) nogil: cdef inline Slvs_hParam new_param(self, double val) nogil:
"""Add a parameter.""" """Add a parameter."""
self.sys.params += 1 cdef Slvs_hParam h = <Slvs_hParam>self.param_list.size() + 1
cdef Slvs_hParam h = <Slvs_hParam>self.sys.params
self.param_list[h] = Slvs_MakeParam(h, self.g, val) self.param_list[h] = Slvs_MakeParam(h, self.g, val)
return h return h
cdef inline Slvs_hEntity eh(self) nogil: cdef inline Slvs_hEntity eh(self) nogil:
"""Return new entity handle.""" """Return new entity handle."""
self.sys.entities += 1 return <Slvs_hEntity>self.entity_list.size() + 1
return <Slvs_hEntity>self.sys.entities
cpdef Entity add_point_2d(self, double u, double v, Entity wp): 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. """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 u_p = self.new_param(u)
cdef Slvs_hParam v_p = self.new_param(v) 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(Slvs_MakePoint2d(self.eh(), self.g, wp.h, u_p, v_p))
self.entity_list.push_back(e) return Entity.create(&self.entity_list.back(), 2)
return Entity.create(&e, 2)
cpdef Entity add_point_3d(self, double x, double y, double z): cpdef Entity add_point_3d(self, double x, double y, double z):
"""Add a 3D point then return the handle. """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 x_p = self.new_param(x)
cdef Slvs_hParam y_p = self.new_param(y) cdef Slvs_hParam y_p = self.new_param(y)
cdef Slvs_hParam z_p = self.new_param(z) 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(Slvs_MakePoint3d(self.eh(), self.g, x_p, y_p, z_p))
self.entity_list.push_back(e) return Entity.create(&self.entity_list.back(), 3)
return Entity.create(&e, 3)
cpdef Entity add_normal_2d(self, Entity wp): cpdef Entity add_normal_2d(self, Entity wp):
"""Add a 2D normal orthogonal to specific work plane (`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(): if wp is None or not wp.is_work_plane():
raise TypeError(f"{wp} is not a 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) self.entity_list.push_back(Slvs_MakeNormal2d(self.eh(), self.g, wp.h))
return Entity.create(&e, 0) return Entity.create(&self.entity_list.back(), 0)
cpdef Entity add_normal_3d(self, double qw, double qx, double qy, double qz): cpdef Entity add_normal_3d(self, double qw, double qx, double qy, double qz):
"""Add a 3D normal from quaternion then return the handle. """Add a 3D normal from quaternion then return the handle.
@ -651,9 +672,8 @@ cdef class SolverSystem:
if e is None: if e is None:
raise TypeError(f"{e} is not a entity") raise TypeError(f"{e} is not a entity")
self.sys.constraints += 1
cdef Slvs_Constraint c cdef Slvs_Constraint c
c.h = <Slvs_hConstraint>self.sys.constraints c.h = <Slvs_hConstraint>self.cons_list.size() + 1
c.group = self.g c.group = self.g
c.type = c_type c.type = c_type
c.wrkpl = wp.h c.wrkpl = wp.h

View File

@ -34,12 +34,18 @@ class CoreTest(TestCase):
sys.distance(p1, p4, 70, wp) sys.distance(p1, p4, 70, wp)
line1 = sys.add_line_2d(p0, p3, wp) line1 = sys.add_line_2d(p0, p3, wp)
sys.angle(line0, line1, 45, wp) sys.angle(line0, line1, 45, wp)
result_flag = sys.solve() result_flag = sys.solve()
self.assertEqual(result_flag, ResultFlag.OKAY) self.assertEqual(result_flag, ResultFlag.OKAY)
x, y = sys.params(p2.params) x, y = sys.params(p2.params)
self.assertAlmostEqual(39.54852, x, 4) self.assertAlmostEqual(39.54852, x, 4)
self.assertAlmostEqual(61.91009, y, 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): def test_involute(self):
"""Involute example.""" """Involute example."""