from collections.abc import Iterable
# Can't import Subspace and Quadric on their own due to circular imports
import ddg.geometry.quadrics as quadrics
import ddg.geometry.subspaces as subspaces
from ddg.abc import NonExact
def _resolve_intersection(intersection):
COMBINATIONS = {
(subspaces.Subspace,) : subspaces.meet,
(quadrics.Quadric, subspaces.Subspace) : quadrics.intersect_quadric_subspace
}
#Maybe it would be a better idea to remember if we got an intersection
#object to not built the same again if no combination was found
if isinstance(intersection, Intersection):
intersection = list(intersection.objects)
if len(intersection) == 1:
return intersection[0]
for combination in COMBINATIONS.keys():
intersect_fct = COMBINATIONS[combination]
if len(combination) == 1:
cls = combination[0]
instances = [(idx, instance) for idx, instance in
enumerate(intersection) if isinstance(instance, cls)]
instances.reverse()
if len(instances) in (0,1):
continue
for idx, instance in instances:
intersection.pop(idx)
instances = list(zip(*instances))[1]
intersection.append(intersect_fct(*instances))
return _resolve_intersection(intersection)
#Not used yet
checked = []
instances = ['']*len(intersection)
used_indices = []
contained = True
for (clsidx, cls) in enumerate(combination):
if cls in checked:
idx = checked.index(cls)
next_index = instances.index(idx)
instances[next_index] = None
used_indices.append(next_index)
else:
instances = [clsidx if (isinstance(intersection[i], cls) and
instances[i] != None) else
instances[i] for i in range(len(intersection))]
if instances.count(clsidx) < combination.count(cls):
contained = False
break
checked.append(cls)
next_index = instances.index(clsidx)
instances[next_index] = None
used_indices.append(next_index)
if contained == True:
used_indices.sort()
used_indices.reverse()
used_objects = [intersection.pop(i) for i in used_indices]
# sort according to the order given in the combination tuple since
# order matters for some intersection functions
used_objects_sorted = []
for cls in combination:
for object_ in used_objects:
if isinstance(object_, cls):
used_objects_sorted.append(object_)
intersection.append(intersect_fct(*used_objects_sorted))
return _resolve_intersection(intersection)
return Intersection(*intersection)
def _resolve_join(join):
COMBINATIONS = {
(subspaces.Subspace,) : subspaces.join,
(quadrics.Quadric, subspaces.Subspace) : quadrics.join_quadric_subspace
}
#Maybe it would be a better idea to remember if we got a join
#object to not built the same again if no combination was found
if isinstance(join, Join):
join = list(join.objects)
if len(join) == 1:
return join[0]
for combination in COMBINATIONS.keys():
join_fct = COMBINATIONS[combination]
if len(combination) == 1:
cls = combination[0]
instances = [(idx, instance) for idx, instance in
enumerate(join) if isinstance(instance, cls)]
instances.reverse()
if len(instances) in (0,1):
continue
for idx, instance in instances:
join.pop(idx)
instances = list(zip(*instances))[1]
join.append(join_fct(*instances))
return _resolve_join(join)
#Not used yet
checked = []
instances = ['']*len(join)
used_indices = []
contained = True
for (clsidx, cls) in enumerate(combination):
if cls in checked:
idx = checked.index(cls)
next_index = instances.index(idx)
instances[next_index] = None
used_indices.append(next_index)
else:
instances = [clsidx if (isinstance(join[i], cls) and
instances[i] != None) else
instances[i] for i in range(len(join))]
if instances.count(clsidx) < combination.count(cls):
contained = False
break
checked.append(cls)
next_index = instances.index(clsidx)
instances[next_index] = None
used_indices.append(next_index)
if contained == True:
used_indices.sort()
used_indices.reverse()
used_objects = [join.pop(i) for i in used_indices]
# sort according to the order given in the combination tuple since
# order matters for some join functions
used_objects_sorted = []
for cls in combination:
for object_ in used_objects:
if isinstance(object_, cls):
used_objects_sorted.append(object_)
join.append(join_fct(*used_objects_sorted))
return _resolve_join(join)
return Join(*join)
[docs]def intersect(*objects, resolve=True):
"""Intersection function
Parameters
----------
*objects : Any
Objects to intersect
resolve : bool, default=False
Whether or not the intersection should be resolved immediately
Returns
-------
ddg.geometry.intersection.Intersection or resolved Intersection
Instance of Intersection containing obj1 and obj2 or the intersection
of the class obtained by resolving the intersection
See Also
--------
join
"""
if resolve:
return Intersection(*objects).resolve()
return Intersection(*objects)
[docs]def meet(*objects, resolve=True):
"""Alias for intersect.
See Also
--------
intersect
"""
return intersect(*objects, resolve=resolve)
[docs]def join(*objects, resolve=True):
"""Join function
Parameters
----------
*objects : Any
Objects to join
resolve : bool, default=False
Whether or not the join should be resolved immediately
Returns
-------
ddg.geometry.intersection.Join or resolved Intersection
Instance of Join containing obj1 and obj2 or the join of the class
obtained by resolving the join
See Also
--------
intersect
"""
if resolve:
return Join(*objects).resolve()
return Join(*objects)
[docs]class Intersection(Iterable, NonExact):
"""Base class for Intersections.
Parameters
----------
*obj : object
Intersecting objects
Attributes
----------
objects : list
List of intersecting objects.
types : set
Set of types of intersecting objects.
Methods
-------
resolve
Resolve the intersection.
See Also
--------
Join
"""
def __init__(self, *obj):
self.objects = obj
def __iter__(self):
return self.objects.__iter__()
def __contains__(self, p):
return all(p in o for o in self.objects)
@property
def types(self):
return set(type(o) for o in self.objects)
@property
def atol(self):
tol_list = [obj.atol for obj in self.objects if hasattr(obj, 'atol')]
return max(tol_list)
@property
def rtol(self):
tol_list = [obj.rtol for obj in self.objects if hasattr(obj, 'rtol')]
return max(tol_list)
[docs] def resolve(self):
return _resolve_intersection(self)
[docs]class Join(Iterable):
"""Base class for joins.
Parameters
----------
*obj : object
Objects to join
Attributes
----------
objects : list
List of joined objects.
Methods
-------
resolve
Resolve the join.
See Also
--------
Intersection
"""
def __init__(self, *obj):
self.objects = obj
def __iter__(self):
return self.objects.__iter__()
def __contains__(self, p):
return any(p in obj for obj in self.objects)
[docs] def resolve(self):
return _resolve_join(self)