Source code for ladybug_geometry.geometry3d.cylinder

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

from .pointvector import Point3D, Vector3D
from .plane import Plane
from .arc import Arc3D

import math


[docs] class Cylinder(object): """Cylinder object. Args: center: A Point3D at the center of the bottom base of the cylinder. axis: A Vector3D representing the direction and height of the cylinder. The vector extends from the bottom base center to the top base center. radius: A number representing the radius of the cylinder. Properties: * center * axis * radius * center_end * diameter * height * area * volume * min * max * base_bottom * base_top """ __slots__ = ('_center', '_axis', '_radius', '_base_bottom', '_base_top', '_min', '_max') def __init__(self, center, axis, radius): """Initialize Cylinder.""" assert isinstance(center, Point3D), \ "Expected Point3D. Got {}.".format(type(center)) assert isinstance(axis, Vector3D), \ "Expected Vector3D. Got {}.".format(type(axis)) assert radius > 0, \ 'Cylinder radius must be greater than 0. Got {}.'.format(radius) self._center = center self._axis = axis self._radius = radius self._base_bottom = None self._base_top = None self._min = None self._max = None
[docs] @classmethod def from_start_end(cls, p1, p2, radius): """Initialize a new cylinder from start and end points. Args: p1: The start point of the cylinder, represents the center of the bottom base of the cylinder. p2: The end point of the cylinder, represents the center of the top base of the cylinder radius: A number representing the radius of the cylinder. """ axis = p2 - p1 return cls(p1, axis, radius)
[docs] @classmethod def from_dict(cls, data): """Create a Cylinder from a dictionary. Args: data: A python dictionary in the following format .. code-block:: python { "type": "Cylinder" "center": (10, 0, 0), "axis": (0, 0, 1), "radius": 1.0 } """ return cls(Point3D.from_array(data['center']), Vector3D.from_array(data['axis']), data['radius'])
@property def center(self): """Center of Cylinder.""" return self._center @property def axis(self): """Axis of Cylinder.""" return self._axis @property def radius(self): """Radius of Cylinder""" return self._radius @property def center_end(self): """Center of the opposite end of Cylinder.""" return self.center + self.axis @property def diameter(self): """Diameter of Cylinder""" return self.radius * 2 @property def height(self): """Height of Cylinder""" return self.axis.magnitude @property def area(self): """Surface area of a Cylinder""" return 2 * math.pi * self.radius * self.height + 2 * math.pi * self.radius ** 2 @property def volume(self): """Volume of a Cylinder""" return math.pi * self.radius ** 2 * self.height @property def base_bottom(self): """Get an Arc3D representing the bottom circular base of the cylinder.""" if self._base_bottom is None: self._base_bottom = Arc3D(Plane(self.axis, self.center), self.radius) return self._base_bottom @property def base_top(self): """Get an Arc3D representing the top circular base of the cylinder.""" if self._base_top is None: plane = Plane(self.axis, self.center + self.axis) self._base_top = Arc3D(plane, self.radius) return self._base_top @property def min(self): """A Point3D for the minimum bounding box vertex around this geometry.""" if self._min is None: self._calculate_min_max() return self._min @property def max(self): """A Point3D for the maximum bounding box vertex around this geometry.""" if self._max is None: self._calculate_min_max() return self._max
[docs] def move(self, moving_vec): """Get a Cylinder that has been moved along a vector. Args: moving_vec: A Vector3D with the direction and distance to move the Cylinder. """ return Cylinder(self.center.move(moving_vec), self.axis, self.radius)
[docs] def rotate(self, axis, angle, origin): """Rotate this Cylinder 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 cylinder will be rotated. """ return Cylinder(self.center.rotate(axis, angle, origin), self.axis.rotate(axis, angle), self.radius)
[docs] def rotate_xy(self, angle, origin): """Get a Cylinder 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 cylinder will be rotated. """ return Cylinder(self.center.rotate_xy(angle, origin), self.axis.rotate_xy(angle), self.radius)
[docs] def reflect(self, normal, origin): """Get a Cylinder 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 Cylinder(self.center.reflect(normal, origin), self.axis.reflect(normal), self.radius)
[docs] def scale(self, factor, origin=None): """Scale a Cylinder by a factor from an origin point. Args: factor: A number representing how much the Cylinder 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 Cylinder(self.center.scale(factor, origin), self.axis * factor, self.radius * factor)
[docs] def duplicate(self): """Get a copy of this object.""" return self.__copy__()
[docs] def to_dict(self): """Get Cylinder as a dictionary.""" return { 'type': 'Cylinder', 'center': self.center.to_array(), 'axis': self.axis.to_array(), 'radius': self.radius }
def _calculate_min_max(self): """Calculate maximum and minimum Point3D for this object.""" base1, base2 = self.base_bottom, self.base_top b1mn, b1mx, b2mn, b2mx = base1.min, base1.max, base2.min, base2.max self._min = Point3D( min(b1mn.x, b2mn.x), min(b1mn.y, b2mn.y), min(b1mn.z, b2mn.z)) self._max = Point3D( max(b1mx.x, b2mx.x), max(b1mx.y, b2mx.y), max(b1mx.z, b2mx.z)) def __copy__(self): return Cylinder(self.center, self.axis, self.radius) def __key(self): """A tuple based on the object properties, useful for hashing.""" return (self._center, self._axis, self._radius) def __hash__(self): return hash(self.__key()) def __eq__(self, other): return isinstance(other, Cylinder) 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 'Cylinder (center {}) (axis {}) (radius {})'.\ format(self.center, self.axis, self.radius)