From eda5689f0a051ef81ce82cd530b51c371933860f Mon Sep 17 00:00:00 2001 From: kwikrick Date: Fri, 5 Oct 2012 12:07:50 +0000 Subject: [PATCH] line mapping (work in progress) --- TODO.txt | 18 +++++++++++++++++- geosolver/geometric.py | 43 ++++++++++++++++++++++++++++++++++++------ test/test_geometry.py | 20 ++++++++++++++++++-- 3 files changed, 72 insertions(+), 9 deletions(-) diff --git a/TODO.txt b/TODO.txt index 4c5179c..e05589f 100644 --- a/TODO.txt +++ b/TODO.txt @@ -13,7 +13,11 @@ Speed: The solver is currently much too slow. The problem is the pattern - compliled implementation (Psycho/C++/Haskell/???) Rules: More rewrite rules to increase the problem domain: - - need 3d rule: merge of 2 rigids with 2 shared points (hinge) + hog with angle not on hinge points + - need 2d and 3d rules for merging radial clusters + 2D:H+H->H sharing center and 1 point + 3D:H+H+H-> sharing center and 3 points, 2 points per pair of hogs + 3D:H+H->H sharing center and 2 points (local overconstrained) + - need 3d rule: merge of 2 rigids with 2 shared points (hinge) + hog with angle not on hinge points - larger subproblems (octahedron, variable radius spheres/cylinders) - new clusters types (N degrees of freedom) @@ -27,6 +31,8 @@ Extentions: BUGS: +- prototype based selection doesn't seem to work on line mappings + - stop problem from rotating and jumping around when there are no fixed points. It should be as close to the prototype as possible; should have at least have one (2d) or two(3d) edge(s) with the same offset and orientation. @@ -59,3 +65,13 @@ def diamond_3d(): FixConstraint(v2=[-5.0, 5.0, 0.0]) not satisfied FixConstraint(v1=[0.0, 0.0, 0.0]) not satisfied +- 2D deriveADD accepts this pattern, but fails during execution. + Angle(p3,p2,p4) + Rigid(p1,p2,p4) + Distance(p1,p3) + Note: this pattern can be solved only in 2D. To keep DeriveADD general + (and simple), pattern matching should be more strict, allowing only + patterns where the angle constraint is in the derived triangle. + An extra rule is needed to merge two angles (radial clusters) in 2D. + In 3D, three radial clusters can be merged. + diff --git a/geosolver/geometric.py b/geosolver/geometric.py index bb6bc80..b0acd82 100644 --- a/geosolver/geometric.py +++ b/geosolver/geometric.py @@ -620,8 +620,17 @@ class GeometricSolver (Listener): dist = Rigid([v,n]) # add add-hoc attributes to rigid, so we can distinguish vertex and normal! dist.vertex = v - dist.normal = n - # add to mapping + dist.normal = n + # add rigids for created points, needed for prototypes + # NOTE: adding non-problem variables to mapping! + # TODO: clean up after removal of line + vertex_rigid = Rigid([dist.vertex]) + self.dr.add(vertex_rigid) + self._map[dist.vertex] = vertex_rigid + normal_rigid = Rigid([dist.normal]) + self.dr.add(normal_rigid) + self._map[dist.normal] = normal_rigid + # add line to mapping self._map[line] = dist self._map[dist] = line self.dr.add(dist) @@ -637,6 +646,12 @@ class GeometricSolver (Listener): # add add-hoc attributes to rigid, so we can distinguish vertex and normal! dist.vertex = v dist.normal = n + # add rigids for created points, needed for prototypes + # NOTE: adding non-problem variables to mapping! + # TODO: clean up after removal of line + normal_rigid = Rigid([dist.normal]) + self.dr.add(normal_rigid) + self._map[dist.normal] = normal_rigid # add to mapping self._map[line] = dist self._map[dist] = line @@ -878,20 +893,36 @@ class GeometricSolver (Listener): self.dr.set(cluster, [conf]) def _update_line(self, variable): + cluster = self._map[variable] + proto = self.problem.get_prototype(variable) + line_vertex = cluster.vertex + line_normal = cluster.normal if self.dimension == 2: - cluster = self._map[variable] - proto = self.problem.get_prototype(variable) - line_vertex = cluster.vertex - line_normal = cluster.normal + # determine vertex and normal prototype coordinates p1 = proto[0:2] p2 = proto[2:4] v = p1 n = perp_2d(p2-p1) + # update prototypes of created point variables + if line_vertex in self._map: + vertex_rigid = self._map[line_vertex] + conf = Configuration({line_vertex: v}) + self.dr.set(vertex_rigid, [conf]) + diag_print("set "+str(vertex_rigid)+" to "+str(conf),"GeometricSolver") + if line_normal in self._map: + normal_rigid = self._map[line_normal] + conf = Configuration({line_normal: n}) + self.dr.set(normal_rigid, [conf]) + diag_print("set "+str(normal_rigid)+" to "+str(conf),"GeometricSolver") + # update line configuration conf = Configuration({line_vertex:v, line_normal:n}) self.dr.set(cluster, [conf]) diag_print("set "+str(cluster)+" to "+str(conf),"GeometricSolver") + elif self.dimension == 3: raise NotImplementedError + + def _update_fix(self): if self.fixcluster: diff --git a/test/test_geometry.py b/test/test_geometry.py index c84c3d6..34a3b0a 100644 --- a/test/test_geometry.py +++ b/test/test_geometry.py @@ -99,7 +99,21 @@ def line_problem_2d_2(): problem.add_constraint(DistanceConstraint(Point('p1'), Point('p2'), 5.0)) return problem -def line_problem_2d_3(): +def line_problem_2d_3a(): + """A problem with a Line and a 3 CoincicentConstraints""" + problem = GeometricProblem(dimension=2) + problem.add_variable(Point('p1'),vector([3.0, 2.0])) + problem.add_variable(Point('p2'),vector([1.0, 1.0])) + problem.add_variable(Line('l1'),vector([0.0, 0.0, 1.0, 1.0])) + problem.add_constraint(CoincidenceConstraint(Point('p1'), Line('l1'))) + problem.add_constraint(CoincidenceConstraint(Point('p2'), Line('l1'))) + problem.add_constraint(DistanceConstraint(Point('p1'), Point('p2'), 5.0)) + problem.add_variable(Point('p3'),vector([1.0, 0.0])) + problem.add_constraint(CoincidenceConstraint(Point('p3'), Line('l1'))) + problem.add_constraint(DistanceConstraint(Point('p3'), Point('p2'), 8.0)) + return problem + +def line_problem_2d_3b(): """A problem with a Line and a 3 CoincicentConstraints""" problem = GeometricProblem(dimension=2) problem.add_variable(Point('p1'),vector([3.0, 2.0])) @@ -113,6 +127,7 @@ def line_problem_2d_3(): problem.add_constraint(DistanceConstraint(Point('p1'), Point('p3'), 8.0)) return problem + def line_problem_2d_4(): """A problem with a Line and a 4 CoincicentConstraints""" problem = GeometricProblem(dimension=2) @@ -136,7 +151,8 @@ def test_line(): #test(line_problem_2d_0()) #test(line_problem_2d_1()) #test(line_problem_2d_2()) - test(line_problem_2d_3()) + test(line_problem_2d_3a()) + #test(line_problem_2d_3b()) #test(line_problem_2d_4()) #test(line_problem_3d_0())