def __init__(self, pointA, pointB): Constraint.__init__(self) if pointA == pointB: raise ValueError, 'A Linear must refer to two different points.' self.pointA = V(pointA) self.pointB = V(pointB) self.dir = self.pointB - self.pointA
def closest_point_on_circle(center, normal, radius, p): planar = closest_point_on_plane(center, normal, p) spoke = planar - center if not spoke: spoke = V(1, 0, 0) * normal if not spoke: spoke = V(0, 1, 0) * normal spoke = spoke.magnitude(radius) return center + spoke
def __init__(self, point, normal, radius): Constraint.__init__(self) if zero(radius): raise ValueError, 'A circle must have a non-zero radius.' self.point = V(point) self.normal = V(normal).normalize() self.radius = abs(float(radius)) self.d = self.normal.dot(self.point)
def _circular_linear_test(): from testing import __ok__ c = Circular(V(), V.Y, 1) l = Linear(V.Y, V(2, -1, 0)) __ok__(str(c * l) == "Unity(V(1.0, 0.0, 0.0))") l = Linear(V.Y, -V.Y) __ok__(str(c * l) == "Nowhere()") l = Linear(V(0.5, 0, 0.5), V(0.5, 0, -0.5)) cl = c * l __ok__(isinstance(cl, Duality)) __ok__(cl.pointA[0] == cl.pointB[0])
def get_random(self): if self.normal[0] != 0 or self.normal[1] != 0: x0 = V(-self.normal[1], self.normal[0], 0) else: x0 = V(-self.normal[2], 0, self.normal[0]) x0 = x0.normalize() self.normal = self.normal.normalize() x1 = self.normal.cross(x0) alpha = 2 * math.pi * random.random() return self.point + self.radius * (x0 * math.cos(alpha) + x1 * math.sin(alpha))
def generate_N(self, N): if self.normal[0] != 0 or self.normal[1] != 0: x0 = V(-self.normal[1], self.normal[0], 0) else: x0 = V(-self.normal[2], 0, self.normal[0]) x0 = x0.normalize() self.normal = self.normal.normalize() x1 = self.normal.cross(x0) alphas = [(2 * 3.1415 * i) / N for i in range(N)] return [ self.point + self.radius * (x0 * math.cos(alpha) + x1 * math.sin(alpha)) for alpha in alphas ]
def _planar_planar(self, other): crossSO = self.normal * other.normal # are we coplanar (Planar) or parallel (Nowhere)? if crossSO.zero(): if self.accepts(other.point): return self return Nowhere() # find the intersection (Linear) dir = crossSO point = V() if not zero(crossSO[2]): point[0] = (other.normal[1] * self.d - self.normal[1] * other.d) / crossSO[2] point[1] = (self.normal[0] * other.d - other.normal[0] * self.d) / crossSO[2] point[2] = 0.0 elif not zero(crossSO[1]): point[0] = (self.normal[2] * other.d - other.normal[2] * self.d) / crossSO[1] point[1] = 0.0 point[2] = (other.normal[0] * self.d - self.normal[0] * other.d) / crossSO[1] elif not zero(crossSO[0]): # else: point[0] = 0.0 point[1] = (other.normal[1] * self.d - self.normal[1] * other.d) / crossSO[0] point[2] = (self.normal[0] * other.d - other.normal[0] * self.d) / crossSO[0] return Linear(point, point + dir)
def _circular_circular_test(): from testing import __ok__ # tangent at origin c1 = Circular(V(-1, 0, 0), V.Y, 1) c2 = Circular(V(1, 0, 0), V.Y, 1) c1c2 = c1 * c2 __ok__(isinstance(c1c2, Unity)) __ok__(c1c2.point == V()) # cross off origin c1 = Circular(V.O, V.Y, 1) c2 = Circular(V.X, V.Y, 1) c1c2 = c1 * c2 __ok__(isinstance(c1c2, Duality)) __ok__(c1c2.pointA[0] == c1c2.pointB[0]) __ok__(equal(c1c2.pointA[1], -c1c2.pointB[1])) __ok__(equal(abs(c1c2.pointA[1]), 0.5 * sqrt(3)))
def get_random(self): phi = 2 * math.pi * random.random() theta = math.pi * random.random() return self.point + self.radius * (V([ math.sin(theta) * math.cos(phi), math.sin(theta) * math.sin(phi), math.cos(theta) ]))
def _planar_planar_test(): from testing import __ok__ p = Planar(V(3, 0, -1), V(0, 3, 0)) q = Planar(V(5, 0, -5), V(1, 1, 0)) pq = p * q __ok__(isinstance(pq, Linear)) __ok__(equal(pq.pointB[1], pq.pointA[1])) q = Planar(V(5, 0, -5), V(0, 1, 0)) pq = p * q __ok__(pq is p) q = Planar(V(5, 1, -5), V(0, 1, 0)) pq = p * q __ok__(isinstance(pq, Nowhere))
def _spherical_linear(self, other): mark = other.closest(self.point) aa = mark.dsquared(self.point) cc = self.radius * self.radius if aa > cc + EPSILON: return Nowhere() if aa < cc - EPSILON: chord = V(other.dir) b = sqrt(cc - aa) chord = chord.magnitude(b) return Duality(mark + chord, mark - chord) return Unity(mark)
def _circular_coplanar_linear(self, other): # might find unity, might find duality, might find nowhere mark = other.closest(self.point) aa = mark.dsquared(self.point) cc = self.radius * self.radius if aa > cc + EPSILON: return Nowhere() if aa < cc - EPSILON: chord = V(other.dir) b = sqrt(cc - aa) chord = chord.magnitude(b) return Duality(mark + chord, mark - chord) return Unity(mark)
def _planar_linear_test(): from testing import __ok__ p = Planar(V(3, 0, -1), V(0, 3, 0)) __ok__(str(p) == "Planar(V(3.0, 0.0, -1.0), V(0.0, 1.0, 0.0))") l = Linear(V(2, 1, 1), V(0, -1, 1)) u = p * l __ok__(str(u) == "Unity(V(1.0, 0.0, 1.0))") p = Planar(V(3, -7, -1), V(1, 1, 0)) __ok__(equal(sqrt(2) / 2, p.normal[1]))
def _circular_planar_test(): from testing import __ok__ # coplanar c = Circular(V(-1, 0, 0), V.Y, 1) p = Planar(V(1, 0, 0), V.Y) cp = c * p __ok__(cp is c) # parallel planar c = Circular(V(-1, 0, 0), V.Y, 1) p = Planar(V(1, 1, 0), V.Y) cp = c * p __ok__(isinstance(cp, Nowhere)) # grab the tangent c = Circular(V(0, 0, 0), V.Y, 1) p = Planar(V(0, 1, 0), V(1, 1, 0)) cp = c * p __ok__(isinstance(cp, Unity)) __ok__(equal(cp.point[0], 1)) # grab a duality c = Circular(V(0, 0, 0), V.Y, 1) p = Planar(V(0, .5, 0), V(1, 1, 0)) cp = c * p __ok__(isinstance(cp, Duality)) __ok__(equal(abs(cp.pointA[2]), 0.5 * sqrt(3)))
def __init__(self, point): Constraint.__init__(self) self.point = V(point)
def _linear_linear_test(): from testing import __ok__ # simple intersect at origin, commutative checks u = V(-1, 0, 0) v = -u c1 = Linear(u, v) r = V(0, -1, 0) s = -r c2 = Linear(r, s) __ok__(str(c1 * c2) == "Unity(V(0.0, 0.0, 0.0))") __ok__(str(c2 * c1) == "Unity(V(0.0, 0.0, 0.0))") c1 = Linear(v, u) __ok__(str(c1 * c2) == "Unity(V(0.0, 0.0, 0.0))") __ok__(str(c2 * c1) == "Unity(V(0.0, 0.0, 0.0))") # intersect away from origin o = V(0.125, 0.25, 0.5) u = V(-2, 3, -4) v = -u u += o v += o c1 = Linear(u, v) r = V(-3, 8, 21) s = -r r += o s += o c2 = Linear(r, s) __ok__(str(c2 * c1) == str(Unity(o))) __ok__(str(c1 * c2) == str(Unity(o))) # non-intersecting u = V(-1, 0, 0) v = -u u += V(0.0, 0.0, 0.5) v += V(0.0, 0.0, 0.5) c1 = Linear(u, v) r = V(0, -1, 0) s = -r c2 = Linear(r, s) __ok__(str(c1 * c2) == "Nowhere()") # intersecting r += 0.5 s += 0.5 c2 = Linear(r, s) __ok__(str(c1 * c2) == "Unity(V(0.5, 0.0, 0.5))") # colinear u = s + V(0, 0.5, 0) v = r + V(0, 0.5, 0) c1 = Linear(u, v) __ok__(str(c1 * c2) == str(c1))
def __init__(self, point, radius): Constraint.__init__(self) if zero(radius): raise ValueError, 'A sphere must have a non-zero radius.' self.point = V(point) self.radius = abs(float(radius))
def closest_point_on_sphere(center, r, p): dir = p - center if dir.zero(): return center + V(r, 0, 0) dir = dir.magnitude(r) return center + dir
def __init__(self, point, normal): Constraint.__init__(self) self.point = V(point) self.normal = V(normal).normalize() self.d = self.normal.dot(self.point)
def __init__(self, pointA, pointB): Constraint.__init__(self) if pointA == pointB: raise ValueError, 'Duality must refer to two different points.' self.pointA = V(pointA) self.pointB = V(pointB)