import numpy as np
from . import geometry
from .. import config
[docs]
class CSGUnion(geometry.Geometry):
"""Construct an object by CSG Union."""
def __init__(self, geom1, geom2):
if geom1.dim != geom2.dim:
raise ValueError(
"{} | {} failed (dimensions do not match).".format(
geom1.idstr, geom2.idstr
)
)
super().__init__(
geom1.dim,
(
np.minimum(geom1.bbox[0], geom2.bbox[0]),
np.maximum(geom1.bbox[1], geom2.bbox[1]),
),
geom1.diam + geom2.diam,
)
self.geom1 = geom1
self.geom2 = geom2
[docs]
def inside(self, x):
return np.logical_or(self.geom1.inside(x), self.geom2.inside(x))
[docs]
def on_boundary(self, x):
return np.logical_or(
np.logical_and(self.geom1.on_boundary(x), ~self.geom2.inside(x)),
np.logical_and(self.geom2.on_boundary(x), ~self.geom1.inside(x)),
)
[docs]
def boundary_normal(self, x):
return np.logical_and(self.geom1.on_boundary(x), ~self.geom2.inside(x))[
:, np.newaxis
] * self.geom1.boundary_normal(x) + np.logical_and(
self.geom2.on_boundary(x), ~self.geom1.inside(x)
)[
:, np.newaxis
] * self.geom2.boundary_normal(
x
)
[docs]
def random_points(self, n, random="pseudo"):
x = np.empty(shape=(n, self.dim), dtype=config.real(np))
i = 0
while i < n:
tmp = (
np.random.rand(n, self.dim) * (self.bbox[1] - self.bbox[0])
+ self.bbox[0]
)
tmp = tmp[self.inside(tmp)]
if len(tmp) > n - i:
tmp = tmp[: n - i]
x[i : i + len(tmp)] = tmp
i += len(tmp)
return x
[docs]
def random_boundary_points(self, n, random="pseudo"):
x = np.empty(shape=(n, self.dim), dtype=config.real(np))
i = 0
while i < n:
geom1_boundary_points = self.geom1.random_boundary_points(n, random=random)
geom1_boundary_points = geom1_boundary_points[
~self.geom2.inside(geom1_boundary_points)
]
geom2_boundary_points = self.geom2.random_boundary_points(n, random=random)
geom2_boundary_points = geom2_boundary_points[
~self.geom1.inside(geom2_boundary_points)
]
tmp = np.concatenate((geom1_boundary_points, geom2_boundary_points))
tmp = np.random.permutation(tmp)
if len(tmp) > n - i:
tmp = tmp[: n - i]
x[i : i + len(tmp)] = tmp
i += len(tmp)
return x
[docs]
def periodic_point(self, x, component):
x = np.copy(x)
on_boundary_geom1 = np.logical_and(
self.geom1.on_boundary(x), ~self.geom2.inside(x)
)
x[on_boundary_geom1] = self.geom1.periodic_point(x, component)[
on_boundary_geom1
]
on_boundary_geom2 = np.logical_and(
self.geom2.on_boundary(x), ~self.geom1.inside(x)
)
x[on_boundary_geom2] = self.geom2.periodic_point(x, component)[
on_boundary_geom2
]
return x
[docs]
class CSGDifference(geometry.Geometry):
"""Construct an object by CSG Difference."""
def __init__(self, geom1, geom2):
if geom1.dim != geom2.dim:
raise ValueError(
"{} - {} failed (dimensions do not match).".format(
geom1.idstr, geom2.idstr
)
)
super().__init__(geom1.dim, geom1.bbox, geom1.diam)
self.geom1 = geom1
self.geom2 = geom2
[docs]
def inside(self, x):
return np.logical_and(self.geom1.inside(x), ~self.geom2.inside(x))
[docs]
def on_boundary(self, x):
return np.logical_or(
np.logical_and(self.geom1.on_boundary(x), ~self.geom2.inside(x)),
np.logical_and(self.geom1.inside(x), self.geom2.on_boundary(x)),
)
[docs]
def boundary_normal(self, x):
return np.logical_and(self.geom1.on_boundary(x), ~self.geom2.inside(x))[
:, np.newaxis
] * self.geom1.boundary_normal(x) + np.logical_and(
self.geom1.inside(x), self.geom2.on_boundary(x)
)[
:, np.newaxis
] * -self.geom2.boundary_normal(
x
)
[docs]
def random_points(self, n, random="pseudo"):
x = np.empty(shape=(n, self.dim), dtype=config.real(np))
i = 0
while i < n:
tmp = self.geom1.random_points(n, random=random)
tmp = tmp[~self.geom2.inside(tmp)]
if len(tmp) > n - i:
tmp = tmp[: n - i]
x[i : i + len(tmp)] = tmp
i += len(tmp)
return x
[docs]
def random_boundary_points(self, n, random="pseudo"):
x = np.empty(shape=(n, self.dim), dtype=config.real(np))
i = 0
while i < n:
geom1_boundary_points = self.geom1.random_boundary_points(n, random=random)
geom1_boundary_points = geom1_boundary_points[
~self.geom2.inside(geom1_boundary_points)
]
geom2_boundary_points = self.geom2.random_boundary_points(n, random=random)
geom2_boundary_points = geom2_boundary_points[
self.geom1.inside(geom2_boundary_points)
]
tmp = np.concatenate((geom1_boundary_points, geom2_boundary_points))
tmp = np.random.permutation(tmp)
if len(tmp) > n - i:
tmp = tmp[: n - i]
x[i : i + len(tmp)] = tmp
i += len(tmp)
return x
[docs]
def periodic_point(self, x, component):
x = np.copy(x)
on_boundary_geom1 = np.logical_and(
self.geom1.on_boundary(x), ~self.geom2.inside(x)
)
x[on_boundary_geom1] = self.geom1.periodic_point(x, component)[
on_boundary_geom1
]
return x
[docs]
class CSGIntersection(geometry.Geometry):
"""Construct an object by CSG Intersection."""
def __init__(self, geom1, geom2):
if geom1.dim != geom2.dim:
raise ValueError(
"{} & {} failed (dimensions do not match).".format(
geom1.idstr, geom2.idstr
)
)
super().__init__(
geom1.dim,
(
np.maximum(geom1.bbox[0], geom2.bbox[0]),
np.minimum(geom1.bbox[1], geom2.bbox[1]),
),
min(geom1.diam, geom2.diam),
)
self.geom1 = geom1
self.geom2 = geom2
[docs]
def inside(self, x):
return np.logical_and(self.geom1.inside(x), self.geom2.inside(x))
[docs]
def on_boundary(self, x):
return np.logical_or(
np.logical_and(self.geom1.on_boundary(x), self.geom2.inside(x)),
np.logical_and(self.geom1.inside(x), self.geom2.on_boundary(x)),
)
[docs]
def boundary_normal(self, x):
return np.logical_and(self.geom1.on_boundary(x), self.geom2.inside(x))[
:, np.newaxis
] * self.geom1.boundary_normal(x) + np.logical_and(
self.geom1.inside(x), self.geom2.on_boundary(x)
)[
:, np.newaxis
] * self.geom2.boundary_normal(
x
)
[docs]
def random_points(self, n, random="pseudo"):
x = np.empty(shape=(n, self.dim), dtype=config.real(np))
i = 0
while i < n:
tmp = self.geom1.random_points(n, random=random)
tmp = tmp[self.geom2.inside(tmp)]
if len(tmp) > n - i:
tmp = tmp[: n - i]
x[i : i + len(tmp)] = tmp
i += len(tmp)
return x
[docs]
def random_boundary_points(self, n, random="pseudo"):
x = np.empty(shape=(n, self.dim), dtype=config.real(np))
i = 0
while i < n:
geom1_boundary_points = self.geom1.random_boundary_points(n, random=random)
geom1_boundary_points = geom1_boundary_points[
self.geom2.inside(geom1_boundary_points)
]
geom2_boundary_points = self.geom2.random_boundary_points(n, random=random)
geom2_boundary_points = geom2_boundary_points[
self.geom1.inside(geom2_boundary_points)
]
tmp = np.concatenate((geom1_boundary_points, geom2_boundary_points))
tmp = np.random.permutation(tmp)
if len(tmp) > n - i:
tmp = tmp[: n - i]
x[i : i + len(tmp)] = tmp
i += len(tmp)
return x
[docs]
def periodic_point(self, x, component):
x = np.copy(x)
on_boundary_geom1 = np.logical_and(
self.geom1.on_boundary(x), self.geom2.inside(x)
)
x[on_boundary_geom1] = self.geom1.periodic_point(x, component)[
on_boundary_geom1
]
on_boundary_geom2 = np.logical_and(
self.geom2.on_boundary(x), self.geom1.inside(x)
)
x[on_boundary_geom2] = self.geom2.periodic_point(x, component)[
on_boundary_geom2
]
return x