Source code for ladybug_geometry.geometry3d.sphere

# coding=utf-8
"""Sphere"""
from __future__ import division

from .pointvector import Point3D
from .plane import Plane
from .arc import Arc3D
from .line import LineSegment3D
from ..intersection3d import intersect_line3d_sphere, intersect_plane_sphere


import math


[docs] class Sphere(object): """Sphere object. Args: center: A Point3D representing the center of the arc. radius: A number representing the radius of the sphere. Properties: * center * radius * min * max * diameter * circumference * area * volume """ __slots__ = ('_center', '_radius') def __init__(self, center, radius): """Initialize Sphere.""" assert isinstance(center, Point3D), \ "Expected Point3D. Got {}.".format(type(center)) assert radius > 0, 'Sphere radius must be greater than 0. Got {}.'.format(radius) self._center = center self._radius = radius
[docs] @classmethod def from_dict(cls, data): """Create a Sphere from a dictionary. Args: data: A python dictionary in the following format .. code-block:: python { "type": "Sphere" "center": (10, 0, 0), "radius": 5 } """ return cls(Point3D.from_array(data['center']), data['radius'])
@property def center(self): """Center of sphere.""" return self._center @property def radius(self): """Radius of sphere.""" return self._radius @property def min(self): """A Point3D for the minimum bounding box vertex around this geometry.""" return Point3D(self.center.x - self.radius, self.center.y - self.radius, self.center.z - self.radius) @property def max(self): """A Point3D for the maximum bounding box vertex around this geometry.""" return Point3D(self.center.x + self.radius, self.center.y + self.radius, self.center.z + self.radius) @property def diameter(self): """Diameter of sphere""" return self.radius * 2 @property def circumference(self): """Circumference of sphere""" return 2 * math.pi * self.radius @property def area(self): """Surface area of sphere""" return 4 * math.pi * self.radius ** 2 @property def volume(self): """Volume of sphere""" return 4 / 3 * math.pi * self.radius ** 3
[docs] def move(self, moving_vec): """Get a sphere that has been moved along a vector. Args: moving_vec: A Vector3D with the direction and distance to move the sphere. """ return Sphere(self.center.move(moving_vec), self.radius)
[docs] def rotate(self, axis, angle, origin): """Rotate this sphere by a certain angle around an axis and origin. Right hand rule applies: If axis has a positive orientation, rotation will be clockwise. If axis has a negative orientation, rotation will be counterclockwise. Args: axis: A Vector3D axis representing the axis of rotation. angle: An angle for rotation in radians. origin: A Point3D for the origin around which the sphere will be rotated. """ return Sphere(self.center.rotate(axis, angle, origin), self.radius)
[docs] def rotate_xy(self, angle, origin): """Get a sphere that is rotated counterclockwise in the world XY plane by an angle. Args: angle: An angle for rotation in radians. origin: A Point3D for the origin around which the sphere will be rotated. """ return Sphere(self.center.rotate_xy(angle, origin), self.radius)
[docs] def reflect(self, normal, origin): """Get a sphere reflected across a plane with the input normal vector and origin. Args: normal: A Vector3D representing the normal vector for the plane across which the arc will be reflected. THIS VECTOR MUST BE NORMALIZED. origin: A Point3D representing the origin from which to reflect. """ return Sphere(self.center.reflect(normal, origin), self.radius)
[docs] def scale(self, factor, origin=None): """Scale a sphere by a factor from an origin point. Args: factor: A number representing how much the sphere should be scaled. origin: A Point3D representing the origin from which to scale. If None, it will be scaled from the World origin (0, 0, 0). """ return Sphere(self.center.scale(factor, origin), self.radius * factor)
[docs] def intersect_plane(self, plane): """Get the intersection of a plane with this Sphere object Args: plane: A Plane object. Returns: Arc3D representing a full circle if it exists. None if no full intersection exists. """ ip = intersect_plane_sphere(plane, self) # ip = [center pt, vector, radius] return None if ip is None or isinstance(ip, Point3D) else \ Arc3D(Plane(ip[1], ip[0]), ip[2])
[docs] def intersect_line_ray(self, line_ray): """Get the intersection between this Sphere object and a Ray2D/LineSegment2D. Args: line_ray: A LineSegment3D or Ray3D that will be extended infinitely for intersection. Returns: A LineSegment3D object if a full intersection exists. A Point if a tangent intersection exists. None if no full intersection exists. """ il = intersect_line3d_sphere(line_ray, self) return None if il is None else \ il if isinstance(il, Point3D) else \ LineSegment3D.from_end_points(il[0], il[1])
[docs] def duplicate(self): """Get a copy of this object.""" return self.__copy__()
[docs] def to_dict(self): """Get Sphere as a dictionary.""" return {'type': 'Sphere', 'center': self.center.to_array(), 'radius': self.radius}
def __copy__(self): return Sphere(self._center, self._radius) def __key(self): """A tuple based on the object properties, useful for hashing.""" return (self._center, self._radius) def __hash__(self): return hash(self.__key()) def __eq__(self, other): return isinstance(other, Sphere) and self.__key() == other.__key() def __ne__(self, other): return not self.__eq__(other)
[docs] def ToString(self): """Overwrite .NET ToString.""" return self.__repr__()
def __repr__(self): return 'Sphere (center {}) (radius {}))'.format(self.center, self.radius)