class Capsule(object): def __init__(self, point_a, point_b, radius): self.line_segment = LineSegment(point_a, point_b) self.radius = radius def clone(self): return Capsule(self.line_segment.point_a, self.line_segment.point_b, self.radius) def length(self): return self.line_segment.length() def volume(self): return math.pi * self.radius * self.radius * ( (4.0 / 3.0) * self.radius + self.length()) def calc_line(self): return self.line_segment.calc_line() def contains_point(self, point, eps=1e-7): return True if self.line_segment.point_distance( point) < self.radius + eps else False def make_mesh(self, subdivision_level=1): pass # TODO: Use convex hull generator algorithm after computing points.
def split_triangle(min_area): for triple in self.triangle_list: triangle = self.make_triangle(triple) for i in range(3): edge = LineSegment(point_a=triangle[i], point_b=triangle[i + 1]) for j, vertex in enumerate(self.vertex_list): if (vertex - edge.point_a).length() < eps: continue if (vertex - edge.point_b).length() < eps: continue if not edge.contains_point(vertex, eps=eps): continue self.triangle_list.remove(triple) self.triangle_list.append( (j, triple[(i + 2) % 3], triple[i])) self.triangle_list.append( (j, triple[(i + 1) % 3], triple[(i + 2) % 3])) min_area['area'] = min( self.make_triangle(self.triangle_list[-2]).area(), min_area['area']) min_area['area'] = min( self.make_triangle(self.triangle_list[-1]).area(), min_area['area']) return True
def intersect_with(self, other, eps=1e-7): if isinstance(other, Triangle): from math3d_point_cloud import PointCloud point_cloud = PointCloud() for line_segment in self.yield_line_segments(): point = other.intersect_with(line_segment) if point is not None: point_cloud.add_point(point) for line_segment in other.yield_line_segments(): point = self.intersect_with(line_segment) if point is not None: point_cloud.add_point(point) point_list = point_cloud.point_list if len(point_list) == 2: line_segment = LineSegment(point_list[0], point_list[1]) if line_segment.length() >= eps: return line_segment elif len(point_list) > 0: return point_cloud elif isinstance(other, LineSegment): plane = self.calc_plane() alpha = plane.intersect_line_segment(other) if alpha is not None and 0.0 <= alpha <= 1.0: point = other.lerp(alpha) if self.contains_point(point, eps): return point
class Cylinder(object): def __init__(self, point_a, point_b, radius): self.line_segment = LineSegment(point_a, point_b) self.radius = radius def clone(self): return Cylinder(self.line_segment.point_a, self.line_segment.point_b, self.radius) def length(self): return self.line_segment.length() def calc_line(self): return self.line_segment.calc_line() def contains_point(self, point, eps=1e-7): spine = self.line_segment.point_b - self.line_segment.point_a unit_normal = spine.normalized() vector = point - self.line_segment.point_a length = vector.dot(unit_normal) if length <= -eps or length >= spine.length() + eps: return False hypotenuse = vector.length() distance = math.sqrt(hypotenuse * hypotenuse - length * length) return True if distance < self.radius + eps else False def make_mesh(self, subdivision_level=1): from math3d_point_cloud import PointCloud from math3d_transform import AffineTransform spine = self.line_segment.point_b - self.line_segment.point_a spine_length = spine.length() transform = AffineTransform().make_frame(spine, self.line_segment.point_a) count = 4 * (subdivision_level + 1) point_cloud = PointCloud() for i in range(count): angle = 2.0 * math.pi * float(i) / float(count) vertex = Vector(self.radius * math.cos(angle), self.radius * math.sin(angle), 0.0) point_cloud.point_list.append(transform(vertex)) point_cloud.point_list.append( transform(vertex + Vector(0.0, 0.0, spine_length))) return point_cloud.find_convex_hull()
def split_against_plane(self, plane, eps=1e-7): back_list = [] front_list = [] triangle_list = [self.clone()] while len(triangle_list) > 0: triangle = triangle_list.pop(0) side_list = [plane.side(triangle[i], eps) for i in range(3)] if all([side == Side.NEITHER for side in side_list]): pass elif all([ side == Side.BACK or side == Side.NEITHER for side in side_list ]): back_list.append(triangle) elif all([ side == Side.FRONT or side == Side.NEITHER for side in side_list ]): front_list.append(triangle) else: for i in range(3): if (side_list[i] == Side.BACK and side_list[(i + 1) % 3] == Side.FRONT or side_list[i] == Side.FRONT and side_list[(i + 1) % 3] == Side.BACK): # This might not be the best tessellation, but it will work. line_segment = LineSegment(triangle[i], triangle[i + 1]) alpha = plane.intersect_line_segment(line_segment) point = line_segment.lerp(alpha) triangle_list.append( Triangle(triangle[i], point, triangle[i + 2])) triangle_list.append( Triangle(point, triangle[i + 1], triangle[i + 2])) break return back_list, front_list
def __init__(self, point_a, point_b, radius): self.line_segment = LineSegment(point_a, point_b) self.radius = radius
def yield_line_segments(self): yield LineSegment(self.point_a, self.point_b) yield LineSegment(self.point_b, self.point_c) yield LineSegment(self.point_c, self.point_a)