Changes to GeometricSolver:
- Added RigidConstraint. - Depricated some methods (get_result, get_constrainedness) and added some new methods (get_solution, get_cluster, get_status). Removed old SelectionConstraint and renamed FunctionConstraint to SelectionConstraint Depricated ClusterSolver2D Small bugfixes in cluster ClusterSolver3D Renamed solvergui directory to workbench Renamed solvertest directory to test
This commit is contained in:
parent
fe8d04497f
commit
22e159a5ad
|
@ -4,6 +4,10 @@ The solver finds a generic solution
|
||||||
for problems formulated by Clusters. The generic solution
|
for problems formulated by Clusters. The generic solution
|
||||||
is a directed acyclic graph of Clusters and Methods. Particilar problems
|
is a directed acyclic graph of Clusters and Methods. Particilar problems
|
||||||
and solutions are represented by a Configuration for each cluster.
|
and solutions are represented by a Configuration for each cluster.
|
||||||
|
|
||||||
|
Note: this module is now depricated, and will be removed or replaced
|
||||||
|
in the future.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from clsolver import *
|
from clsolver import *
|
||||||
|
|
|
@ -301,8 +301,8 @@ class MergePR(ClusterMethod):
|
||||||
res = conf1.merge(conf2)
|
res = conf1.merge(conf2)
|
||||||
elif isroot2:
|
elif isroot2:
|
||||||
res = conf2.merge(conf1)
|
res = conf2.merge(conf1)
|
||||||
else: # cheapest
|
else: # cheapest - just copy reference
|
||||||
res = conf2.merge(conf1)
|
res = conf2
|
||||||
return [res]
|
return [res]
|
||||||
|
|
||||||
class MergeDR(ClusterMethod):
|
class MergeDR(ClusterMethod):
|
||||||
|
@ -344,8 +344,8 @@ class MergeDR(ClusterMethod):
|
||||||
res = conf1.merge(conf2)
|
res = conf1.merge(conf2)
|
||||||
elif isroot2:
|
elif isroot2:
|
||||||
res = conf2.merge(conf1)
|
res = conf2.merge(conf1)
|
||||||
else: # cheapest
|
else: # cheapest - just copy reference
|
||||||
res = conf2.merge(conf1)
|
res = conf2
|
||||||
return [res]
|
return [res]
|
||||||
|
|
||||||
class MergeRR(ClusterMethod):
|
class MergeRR(ClusterMethod):
|
||||||
|
@ -386,7 +386,7 @@ class MergeRR(ClusterMethod):
|
||||||
res = conf1.merge(conf2)
|
res = conf1.merge(conf2)
|
||||||
elif isroot2 and not isroot1:
|
elif isroot2 and not isroot1:
|
||||||
res = conf2.merge(conf1)
|
res = conf2.merge(conf1)
|
||||||
elif len(c1.vars) < len(c2.vars): # cheapest
|
elif len(c1.vars) < len(c2.vars): # cheapest - transform smallest config
|
||||||
res = conf2.merge(conf1)
|
res = conf2.merge(conf1)
|
||||||
else:
|
else:
|
||||||
res = conf1.merge(conf2)
|
res = conf1.merge(conf2)
|
||||||
|
@ -495,8 +495,8 @@ class DeriveTTD(ClusterMethod):
|
||||||
|
|
||||||
def prototype_constraints(self):
|
def prototype_constraints(self):
|
||||||
constraints = []
|
constraints = []
|
||||||
constraints.append(FunctionConstraint(fnot(is_left_handed),[self.a,self.b,self.c,self.d]))
|
constraints.append(SelectionConstraint(fnot(is_left_handed),[self.a,self.b,self.c,self.d]))
|
||||||
constraints.append(FunctionConstraint(fnot(is_right_handed),[self.a,self.b,self.c,self.d]))
|
constraints.append(SelectionConstraint(fnot(is_right_handed),[self.a,self.b,self.c,self.d]))
|
||||||
return constraints
|
return constraints
|
||||||
|
|
||||||
class DeriveDAD(ClusterMethod):
|
class DeriveDAD(ClusterMethod):
|
||||||
|
|
|
@ -3,7 +3,7 @@ problems incrementally."""
|
||||||
|
|
||||||
import vector
|
import vector
|
||||||
from clsolver import PrototypeMethod
|
from clsolver import PrototypeMethod
|
||||||
from clsolver2D import ClusterSolver2D
|
# depricated! from clsolver2D import ClusterSolver2D
|
||||||
from clsolver3D import ClusterSolver3D
|
from clsolver3D import ClusterSolver3D
|
||||||
from cluster import Rigid, Hedgehog
|
from cluster import Rigid, Hedgehog
|
||||||
from configuration import Configuration
|
from configuration import Configuration
|
||||||
|
@ -95,6 +95,16 @@ class GeometricProblem (Notifier, Listener):
|
||||||
else:
|
else:
|
||||||
con.add_listener(self)
|
con.add_listener(self)
|
||||||
self.cg.add_constraint(con)
|
self.cg.add_constraint(con)
|
||||||
|
elif isinstance(con, RigidConstraint):
|
||||||
|
for var in con.variables():
|
||||||
|
if var not in self.prototype:
|
||||||
|
raise StandardError, "point variable not in problem"
|
||||||
|
#if self.get_rigid(con.variables())
|
||||||
|
# raise StandardError, "rigid already in problem"
|
||||||
|
#else:
|
||||||
|
if True:
|
||||||
|
con.add_listener(self)
|
||||||
|
self.cg.add_constraint(con)
|
||||||
elif isinstance(con, SelectionConstraint):
|
elif isinstance(con, SelectionConstraint):
|
||||||
for var in con.variables():
|
for var in con.variables():
|
||||||
if var not in self.prototype:
|
if var not in self.prototype:
|
||||||
|
@ -212,7 +222,7 @@ class GeometricProblem (Notifier, Listener):
|
||||||
|
|
||||||
class GeometricSolver (Listener):
|
class GeometricSolver (Listener):
|
||||||
"""The GeometricSolver monitors changes in a GeometricProblem and
|
"""The GeometricSolver monitors changes in a GeometricProblem and
|
||||||
mappes any changes to corresponding changes in a GeometricCluster
|
maps any changes to corresponding changes in a GeometricCluster
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# public methods
|
# public methods
|
||||||
|
@ -261,26 +271,33 @@ class GeometricSolver (Listener):
|
||||||
self._add_constraint(con)
|
self._add_constraint(con)
|
||||||
|
|
||||||
def get_constrainedness(self):
|
def get_constrainedness(self):
|
||||||
toplevel = self.dr.top_level()
|
"""Depricated. Use get_statis instead"""
|
||||||
if len(toplevel) > 1:
|
return self.get_status()
|
||||||
return "under-constrained"
|
# toplevel = self.dr.top_level()
|
||||||
elif len(toplevel) == 1:
|
# if len(toplevel) > 1:
|
||||||
cluster = toplevel[0]
|
# return "under-constrained"
|
||||||
if isinstance(cluster,Rigid):
|
# elif len(toplevel) == 1:
|
||||||
configurations = self.dr.get(cluster)
|
# cluster = toplevel[0]
|
||||||
if configurations == None:
|
# if isinstance(cluster,Rigid):
|
||||||
return "unsolved"
|
# configurations = self.dr.get(cluster)
|
||||||
elif len(configurations) > 0:
|
# if configurations == None:
|
||||||
return "well-constrained"
|
# return "unsolved"
|
||||||
else:
|
# elif len(configurations) > 0:
|
||||||
return "over-constrained"
|
# return "well-constrained"
|
||||||
else:
|
# else:
|
||||||
return "under-constrained"
|
# return "over-constrained"
|
||||||
elif len(toplevel) == 0:
|
# else:
|
||||||
return "error"
|
# return "under-constrained"
|
||||||
|
# elif len(toplevel) == 0:
|
||||||
|
# return "error"
|
||||||
|
|
||||||
def get_result(self):
|
def get_result(self):
|
||||||
"""returns the result as a GeometricCluster"""
|
"""Depricated. Use get_cluster instead."""
|
||||||
|
return self.get_cluster()
|
||||||
|
|
||||||
|
def get_cluster(self):
|
||||||
|
"""Returns a GeometricCluster (the root of a tree of clusters),
|
||||||
|
describing the solutions and the decomposition of the problem."""
|
||||||
map = {}
|
map = {}
|
||||||
# map dr clusters
|
# map dr clusters
|
||||||
for drcluster in self.dr.rigids():
|
for drcluster in self.dr.rigids():
|
||||||
|
@ -327,7 +344,6 @@ class GeometricSolver (Listener):
|
||||||
geoout = map[outcluster]
|
geoout = map[outcluster]
|
||||||
geoout.subs = list(geoin.subs)
|
geoout.subs = list(geoin.subs)
|
||||||
|
|
||||||
|
|
||||||
# determine top-level result
|
# determine top-level result
|
||||||
rigids = filter(lambda c: isinstance(c, Rigid), self.dr.top_level())
|
rigids = filter(lambda c: isinstance(c, Rigid), self.dr.top_level())
|
||||||
if len(rigids) == 0:
|
if len(rigids) == 0:
|
||||||
|
@ -338,7 +354,7 @@ class GeometricSolver (Listener):
|
||||||
result.solutions = []
|
result.solutions = []
|
||||||
result.flags = GeometricCluster.UNSOLVED
|
result.flags = GeometricCluster.UNSOLVED
|
||||||
elif len(rigids) == 1:
|
elif len(rigids) == 1:
|
||||||
# structurally well constrained
|
# structurally well constrained, or structurally overconstrained
|
||||||
result = map[rigids[0]]
|
result = map[rigids[0]]
|
||||||
else:
|
else:
|
||||||
# structurally underconstrained cluster
|
# structurally underconstrained cluster
|
||||||
|
@ -348,6 +364,53 @@ class GeometricSolver (Listener):
|
||||||
result.subs.append(map[rigid])
|
result.subs.append(map[rigid])
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def get_solutions(self):
|
||||||
|
"""Returns a list of Configurations, which will be empty if the
|
||||||
|
problem is not structurally well-constrained. Note: this method is
|
||||||
|
cheaper but less informative than get_cluster. The
|
||||||
|
list and the configurations should not be changed (since they are
|
||||||
|
references to objects in the solver)."""
|
||||||
|
rigids = filter(lambda c: isinstance(c, Rigid), self.dr.top_level())
|
||||||
|
if len(rigids) == 0:
|
||||||
|
return self.dr.get(rigids[0])
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_status(self):
|
||||||
|
"""Returns a symbolic flag, one of:
|
||||||
|
GeometricCluster.S_UNDER,
|
||||||
|
GeometricCluster.S_OVER,
|
||||||
|
GeometricCluster.OK,
|
||||||
|
GeometricCluster.UNSOLVED,
|
||||||
|
GeometricCluster.EMPTY,
|
||||||
|
GeometricCluster.I_OVER,
|
||||||
|
GeometricCluster.I_UNDER.
|
||||||
|
Note: this method is cheaper but less informative than get_cluster.
|
||||||
|
"""
|
||||||
|
rigids = filter(lambda c: isinstance(c, Rigid), self.dr.top_level())
|
||||||
|
if len(rigids) == 0:
|
||||||
|
return GeometricCluster.EMPTY
|
||||||
|
elif len(rigids) == 1:
|
||||||
|
drcluster = rigids[0]
|
||||||
|
solutions = self.dr.get(drcluster)
|
||||||
|
underconstrained = False
|
||||||
|
if solutions == None:
|
||||||
|
return GeometricCluster.UNSOLVED
|
||||||
|
else:
|
||||||
|
for solution in solutions:
|
||||||
|
if solution.underconstrained:
|
||||||
|
underconstrained = True
|
||||||
|
if drcluster.overconstrained:
|
||||||
|
return GeometricCluster.S_OVER
|
||||||
|
elif len(solutions) == 0:
|
||||||
|
return GeometricCluster.I_OVER
|
||||||
|
elif underconstrained:
|
||||||
|
return GeometricCluster.I_UNDER
|
||||||
|
else:
|
||||||
|
return GeometricCluster.OK
|
||||||
|
else:
|
||||||
|
return GeometricCluster.S_UNDER
|
||||||
|
|
||||||
def receive_notify(self, object, message):
|
def receive_notify(self, object, message):
|
||||||
"""Take notice of changes in constraint graph"""
|
"""Take notice of changes in constraint graph"""
|
||||||
if object == self.cg:
|
if object == self.cg:
|
||||||
|
@ -412,6 +475,15 @@ class GeometricSolver (Listener):
|
||||||
self.dr.add(rig)
|
self.dr.add(rig)
|
||||||
# set configuration
|
# set configuration
|
||||||
self._update_constraint(con)
|
self._update_constraint(con)
|
||||||
|
elif isinstance(con, RigidConstraint):
|
||||||
|
# map to rigid
|
||||||
|
vars = list(con.variables());
|
||||||
|
rig = Rigid(vars)
|
||||||
|
self._map[con] = rig
|
||||||
|
self._map[rig] = con
|
||||||
|
self.dr.add(rig)
|
||||||
|
# set configuration
|
||||||
|
self._update_constraint(con)
|
||||||
elif isinstance(con, FixConstraint):
|
elif isinstance(con, FixConstraint):
|
||||||
if self.fixcluster != None:
|
if self.fixcluster != None:
|
||||||
self.dr.remove(self.fixcluster)
|
self.dr.remove(self.fixcluster)
|
||||||
|
@ -422,6 +494,9 @@ class GeometricSolver (Listener):
|
||||||
self.dr.add(self.fixcluster)
|
self.dr.add(self.fixcluster)
|
||||||
self.dr.set_root(self.fixcluster)
|
self.dr.set_root(self.fixcluster)
|
||||||
self._update_fix()
|
self._update_fix()
|
||||||
|
elif isinstance(con, SelectionConstraint):
|
||||||
|
# add directly to clustersolver
|
||||||
|
self.dr.add(con)
|
||||||
else:
|
else:
|
||||||
## raise StandardError, "unknown constraint type"
|
## raise StandardError, "unknown constraint type"
|
||||||
pass
|
pass
|
||||||
|
@ -482,6 +557,13 @@ class GeometricSolver (Listener):
|
||||||
conf = Configuration({v0:p0,v1:p1})
|
conf = Configuration({v0:p0,v1:p1})
|
||||||
self.dr.set(rig, [conf])
|
self.dr.set(rig, [conf])
|
||||||
assert con.satisfied(conf.map)
|
assert con.satisfied(conf.map)
|
||||||
|
elif isinstance(con, RigidConstraint):
|
||||||
|
# set configuration
|
||||||
|
rig = self._map[con]
|
||||||
|
vars = list(con.variables())
|
||||||
|
conf = con.get_parameter()
|
||||||
|
self.dr.set(rig, [conf])
|
||||||
|
assert con.satisfied(conf.map)
|
||||||
elif isinstance(con, FixConstraint):
|
elif isinstance(con, FixConstraint):
|
||||||
self._update_fix()
|
self._update_fix()
|
||||||
else:
|
else:
|
||||||
|
@ -529,15 +611,17 @@ class GeometricCluster:
|
||||||
I_UNDER incidental under-constrained
|
I_UNDER incidental under-constrained
|
||||||
S_OVER structural overconstrained
|
S_OVER structural overconstrained
|
||||||
S_UNDER structural underconstrained
|
S_UNDER structural underconstrained
|
||||||
UNSOLVED unsolved
|
UNSOLVED unsolved (no input values)
|
||||||
|
EMPTY empty (no variables)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
OK = "well constrained"
|
OK = "well-constrained"
|
||||||
I_OVER = "incidental over-constrained"
|
I_OVER = "incidental over-constrained"
|
||||||
I_UNDER = "incidental under-constrained"
|
I_UNDER = "incidental under-constrained"
|
||||||
S_OVER = "structral over-constrained"
|
S_OVER = "structral over-constrained"
|
||||||
S_UNDER = "structural under-constrained"
|
S_UNDER = "structural under-constrained"
|
||||||
UNSOLVED = "unsolved"
|
UNSOLVED = "unsolved"
|
||||||
|
EMPTY = "empty"
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""initialise an empty new cluster"""
|
"""initialise an empty new cluster"""
|
||||||
|
@ -602,7 +686,7 @@ class FixConstraint(ParametricConstraint):
|
||||||
"""A constraint to fix a point relative to the coordinate system"""
|
"""A constraint to fix a point relative to the coordinate system"""
|
||||||
|
|
||||||
def __init__(self, var, pos):
|
def __init__(self, var, pos):
|
||||||
"""Create a new DistanceConstraint instance
|
"""Create a new FixConstraint instance
|
||||||
|
|
||||||
keyword args:
|
keyword args:
|
||||||
var - a point variable name
|
var - a point variable name
|
||||||
|
@ -698,4 +782,36 @@ class AngleConstraint(ParametricConstraint):
|
||||||
+str(self._variables[2])+","\
|
+str(self._variables[2])+","\
|
||||||
+str(self._value)+")"
|
+str(self._value)+")"
|
||||||
|
|
||||||
|
class RigidConstraint(ParametricConstraint):
|
||||||
|
"""A constraint to set the relative position of a set of points"""
|
||||||
|
|
||||||
|
def __init__(self, conf):
|
||||||
|
"""Create a new DistanceConstraint instance
|
||||||
|
|
||||||
|
keyword args:
|
||||||
|
conf - a Configuration
|
||||||
|
"""
|
||||||
|
ParametricConstraint.__init__(self)
|
||||||
|
self._variables = list(conf.vars())
|
||||||
|
self.set_parameter(conf.copy())
|
||||||
|
|
||||||
|
def satisfied(self, mapping):
|
||||||
|
"""return True iff mapping from variable names to points satisfies constraint"""
|
||||||
|
result = True
|
||||||
|
conf = self._value
|
||||||
|
for index in range(1,len(self._variables)-1):
|
||||||
|
p1 = mapping[self._variables[index-1]]
|
||||||
|
p2 = mapping[self._variables[index]]
|
||||||
|
p3 = mapping[self._variables[index+1]]
|
||||||
|
c1 = conf.map[self._variables[index-1]]
|
||||||
|
c2 = conf.map[self._variables[index]]
|
||||||
|
c3 = conf.map[self._variables[index+1]]
|
||||||
|
result = tol_eq(distance_2p(p1,p2), distance_2p(c1,c2))
|
||||||
|
result = tol_eq(distance_2p(p1,p3), distance_2p(c1,c3))
|
||||||
|
result = tol_eq(distance_2p(p2,p3), distance_2p(c2,c3))
|
||||||
|
return result
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "RigidConstraint("+str(self._variables)+")"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,92 +2,9 @@ from constraint import Constraint
|
||||||
from tolerance import tol_eq
|
from tolerance import tol_eq
|
||||||
from intersections import *
|
from intersections import *
|
||||||
|
|
||||||
|
|
||||||
class SelectionConstraint(Constraint):
|
class SelectionConstraint(Constraint):
|
||||||
"""constraints for solution selection"""
|
"""select solutions where function returns true when applied to given variables."""
|
||||||
|
|
||||||
class NotCounterClockwiseConstraint(SelectionConstraint):
|
|
||||||
"""select triplets that are not counter clockwise (clockwise or degenerate)"""
|
|
||||||
|
|
||||||
def __init__(self,v1,v2,v3):
|
|
||||||
"""init constraint with names of point variables"""
|
|
||||||
self._variables = [v1,v2,v3]
|
|
||||||
|
|
||||||
def satisfied(self, map):
|
|
||||||
"""return True iff mapping from variable names to points satisfies constraint"""
|
|
||||||
p1 = map[self._variables[0]]
|
|
||||||
p2 = map[self._variables[1]]
|
|
||||||
p3 = map[self._variables[2]]
|
|
||||||
return not is_counterclockwise(p1,p2,p3)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "NotCounterClockwiseConstraint("\
|
|
||||||
+str(self._variables[0])+","\
|
|
||||||
+str(self._variables[1])+","\
|
|
||||||
+str(self._variables[2])+")"
|
|
||||||
|
|
||||||
class NotClockwiseConstraint(SelectionConstraint):
|
|
||||||
"""select triplets that are not clockwise (counterclockwise or degenerate)"""
|
|
||||||
|
|
||||||
def __init__(self,v1,v2,v3):
|
|
||||||
"""init constraint with names of point variables"""
|
|
||||||
self._variables = [v1,v2,v3]
|
|
||||||
|
|
||||||
def satisfied(self, map):
|
|
||||||
"""return True iff mapping from variable names to points satisfies constraint"""
|
|
||||||
p1 = map[self._variables[0]]
|
|
||||||
p2 = map[self._variables[1]]
|
|
||||||
p3 = map[self._variables[2]]
|
|
||||||
return not is_clockwise(p1,p2,p3)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "NotClockwiseConstraint("\
|
|
||||||
+str(self._variables[0])+","\
|
|
||||||
+str(self._variables[1])+","\
|
|
||||||
+str(self._variables[2])+")"
|
|
||||||
|
|
||||||
class NotObtuseConstraint(SelectionConstraint):
|
|
||||||
"""select triplets that are not obtuse (acute or degenerate)"""
|
|
||||||
|
|
||||||
def __init__(self,v1,v2,v3):
|
|
||||||
"""init constraint with names of point variables"""
|
|
||||||
self._variables = [v1,v2,v3]
|
|
||||||
|
|
||||||
def satisfied(self, map):
|
|
||||||
"""return True iff mapping from variable names to points satisfies constraint"""
|
|
||||||
p1 = map[self._variables[0]]
|
|
||||||
p2 = map[self._variables[1]]
|
|
||||||
p3 = map[self._variables[2]]
|
|
||||||
return not is_obtuse(p1,p2,p3)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "NotObtuseConstraint("\
|
|
||||||
+str(self._variables[0])+","\
|
|
||||||
+str(self._variables[1])+","\
|
|
||||||
+str(self._variables[2])+")"
|
|
||||||
|
|
||||||
class NotAcuteConstraint(SelectionConstraint):
|
|
||||||
"""select triplets that are not acute (obtuse or degenerate)"""
|
|
||||||
|
|
||||||
def __init__(self,v1,v2,v3):
|
|
||||||
"""init constraint with names of point variables"""
|
|
||||||
self._variables = [v1,v2,v3]
|
|
||||||
|
|
||||||
def satisfied(self, map):
|
|
||||||
"""return True iff mapping from variable names to points satisfies constraint"""
|
|
||||||
p1 = map[self._variables[0]]
|
|
||||||
p2 = map[self._variables[1]]
|
|
||||||
p3 = map[self._variables[2]]
|
|
||||||
return not is_acute(p1,p2,p3)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "NotAcuteConstraint("\
|
|
||||||
+str(self._variables[0])+","\
|
|
||||||
+str(self._variables[1])+","\
|
|
||||||
+str(self._variables[2])+")"
|
|
||||||
|
|
||||||
|
|
||||||
class FunctionConstraint(SelectionConstraint):
|
|
||||||
"""select solutions where function returns true when applied to given variables"""
|
|
||||||
|
|
||||||
def __init__(self,function, vars):
|
def __init__(self,function, vars):
|
||||||
"""init constraint with function and a sequence of variables"""
|
"""init constraint with function and a sequence of variables"""
|
||||||
|
@ -102,7 +19,7 @@ class FunctionConstraint(SelectionConstraint):
|
||||||
return apply(self._function, values)==True
|
return apply(self._function, values)==True
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "FunctionConstraint("+self._function.__name__+","+str(map(str, self._variables))+")"
|
return "SelectionConstraint("+self._function.__name__+","+str(map(str, self._variables))+")"
|
||||||
|
|
||||||
def fnot(function):
|
def fnot(function):
|
||||||
notf = lambda *args: not apply(function,args)
|
notf = lambda *args: not apply(function,args)
|
||||||
|
@ -110,7 +27,7 @@ def fnot(function):
|
||||||
return notf
|
return notf
|
||||||
|
|
||||||
def test():
|
def test():
|
||||||
print FunctionConstraint(is_right_handed, ['a','b','c','d'])
|
print SelectionConstraint(is_right_handed, ['a','b','c','d'])
|
||||||
print FunctionConstraint(fnot(is_right_handed), ['a','b','c','d'])
|
print SelectionConstraint(fnot(is_right_handed), ['a','b','c','d'])
|
||||||
|
|
||||||
if __name__ == "__main__": test()
|
if __name__ == "__main__": test()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Geometric constraint solver test
|
"""This module provides some tests for the GeoSolver.
|
||||||
# See below for simple use of the GeometricSolver API
|
The tests are also simple examples of how to use of the GeomSolver API"""
|
||||||
|
|
||||||
from geosolver.geometric import *
|
from geosolver.geometric import *
|
||||||
from geosolver.vector import vector
|
from geosolver.vector import vector
|
||||||
|
@ -10,6 +10,30 @@ from time import time
|
||||||
|
|
||||||
# ---------- 3D problems -----
|
# ---------- 3D problems -----
|
||||||
|
|
||||||
|
def block(name,x,y,z):
|
||||||
|
"""A block with variables name+#1...8 and dimensions x,y,z"""
|
||||||
|
problem = GeometricProblem(dimension=3)
|
||||||
|
problem.add_point(name+'#1', vector([0.0, 0.0, 0.0]))
|
||||||
|
problem.add_point(name+'#2', vector([0.0, 0.0, 0.0]))
|
||||||
|
problem.add_point(name+'#3', vector([0.0, 0.0, 0.0]))
|
||||||
|
problem.add_point(name+'#4', vector([0.0, 0.0, 0.0]))
|
||||||
|
problem.add_point(name+'#5', vector([0.0, 0.0, 0.0]))
|
||||||
|
problem.add_point(name+'#6', vector([0.0, 0.0, 0.0]))
|
||||||
|
problem.add_point(name+'#7', vector([0.0, 0.0, 0.0]))
|
||||||
|
problem.add_point(name+'#8', vector([0.0, 0.0, 0.0]))
|
||||||
|
conf = Configuration({
|
||||||
|
name+'#1':vector([-x/2, -y/2, -z/2]),
|
||||||
|
name+'#2':vector([-x/2, -y/2, +z/2]),
|
||||||
|
name+'#3':vector([-x/2, +y/2, -z/2]),
|
||||||
|
name+'#4':vector([-x/2, +y/2, +z/2]),
|
||||||
|
name+'#5':vector([+x/2, -y/2, -z/2]),
|
||||||
|
name+'#6':vector([+x/2, -y/2, +z/2]),
|
||||||
|
name+'#7':vector([+x/2, +y/2, -z/2]),
|
||||||
|
name+'#8':vector([+x/2, +y/2, +z/2])
|
||||||
|
})
|
||||||
|
problem.add_constraint(RigidConstraint(conf))
|
||||||
|
return problem
|
||||||
|
|
||||||
def fix3_problem_3d():
|
def fix3_problem_3d():
|
||||||
"""A problem with a fix constraint"""
|
"""A problem with a fix constraint"""
|
||||||
problem = GeometricProblem(dimension=3)
|
problem = GeometricProblem(dimension=3)
|
||||||
|
@ -737,7 +761,7 @@ def stats_solving():
|
||||||
problem = random_triangular_problem_3D(size,10.0,0.0,0.0)
|
problem = random_triangular_problem_3D(size,10.0,0.0,0.0)
|
||||||
t1 = time()
|
t1 = time()
|
||||||
solver = GeometricSolver(problem)
|
solver = GeometricSolver(problem)
|
||||||
result = solver.get_constrainedness()
|
result = solver.get_status()
|
||||||
t2 = time()
|
t2 = time()
|
||||||
t = t2-t1
|
t = t2-t1
|
||||||
print size,"\t",i,"\t",t,"\t",result
|
print size,"\t",i,"\t",t,"\t",result
|
||||||
|
@ -754,7 +778,7 @@ def stats_incremental():
|
||||||
constraint = random.choice(problem.cg.constraints())
|
constraint = random.choice(problem.cg.constraints())
|
||||||
problem.rem_constraint(constraint)
|
problem.rem_constraint(constraint)
|
||||||
problem.add_constraint(constraint)
|
problem.add_constraint(constraint)
|
||||||
result = solver.get_constrainedness()
|
result = solver.get_status()
|
||||||
t2 = time()
|
t2 = time()
|
||||||
t = t2-t1
|
t = t2-t1
|
||||||
print size,"\t",i,"\t",t,"\t",result
|
print size,"\t",i,"\t",t,"\t",result
|
||||||
|
@ -776,7 +800,7 @@ def stats_parametric_incremental():
|
||||||
#problem.rem_constraint(constraint)
|
#problem.rem_constraint(constraint)
|
||||||
#problem.add_constraint(constraint)
|
#problem.add_constraint(constraint)
|
||||||
#constraint.set_parameter(constraint.get_parameter())
|
#constraint.set_parameter(constraint.get_parameter())
|
||||||
result = solver.get_constrainedness()
|
result = solver.get_status()
|
||||||
t2 = time()
|
t2 = time()
|
||||||
t = t2-t1
|
t = t2-t1
|
||||||
print size,"\t",i,"\t",t,"\t",result
|
print size,"\t",i,"\t",t,"\t",result
|
||||||
|
@ -792,7 +816,7 @@ def stats_parametric():
|
||||||
constraint = random.choice(problem.cg.constraints())
|
constraint = random.choice(problem.cg.constraints())
|
||||||
t1 = time()
|
t1 = time()
|
||||||
constraint.set_parameter(constraint.get_parameter())
|
constraint.set_parameter(constraint.get_parameter())
|
||||||
result = solver.get_constrainedness()
|
result = solver.get_status()
|
||||||
t2 = time()
|
t2 = time()
|
||||||
t = t2-t1
|
t = t2-t1
|
||||||
print size,"\t",i,"\t",t,"\t",result
|
print size,"\t",i,"\t",t,"\t",result
|
||||||
|
@ -813,6 +837,7 @@ def runtests():
|
||||||
#test(random_distance_problem_3D(10,1.0,0.0))
|
#test(random_distance_problem_3D(10,1.0,0.0))
|
||||||
#test(fix1_problem_3d())
|
#test(fix1_problem_3d())
|
||||||
#test(fix2_problem_3d())
|
#test(fix2_problem_3d())
|
||||||
test(fix3_problem_3d())
|
#test(fix3_problem_3d())
|
||||||
|
test(block("BB", 4.0,2.5,5.0))
|
||||||
|
|
||||||
if __name__ == "__main__": runtests()
|
if __name__ == "__main__": runtests()
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Loading…
Reference in New Issue
Block a user