Source code for ladybug_display.geometry3d.vector
"""A vector that can be displayed in 3D space."""
import math
from ladybug_geometry.geometry3d.pointvector import Vector3D
from ladybug.color import Color
from .._base import _DisplayBase
[docs]
class DisplayVector3D(_DisplayBase):
"""A vector in 3D space with display properties.
Args:
geometry: A ladybug-geometry Vector3D object.
color: A ladybug Color object. If None, a default black color will be
used. (Default: None).
Properties:
* geometry
* color
* x
* y
* z
* magnitude
* user_data
"""
__slots__ = ('_color',)
def __init__(self, geometry, color=None):
"""Initialize base with shade object."""
assert isinstance(geometry, Vector3D), '\
Expected ladybug_geometry Vector3D. Got {}'.format(type(geometry))
_DisplayBase.__init__(self, geometry)
self.color = color
[docs]
@classmethod
def from_dict(cls, data):
"""Initialize a DisplayVector3D from a dictionary.
Args:
data: A dictionary representation of an DisplayVector3D object.
"""
assert data['type'] == 'DisplayVector3D', \
'Expected DisplayVector3D dictionary. Got {}.'.format(data['type'])
color = Color.from_dict(data['color']) if 'color' in data and data['color'] \
is not None else None
geo = cls(Vector3D.from_dict(data['geometry']), color)
if 'user_data' in data and data['user_data'] is not None:
geo.user_data = data['user_data']
return geo
@property
def color(self):
"""Get or set a color for this object."""
return self._color
@color.setter
def color(self, value):
if value is None:
value = Color(0, 0, 0)
else:
assert isinstance(value, Color), 'Expected Color for ladybug_display ' \
'object color. Got {}.'.format(type(value))
self._color = value
@property
def x(self):
"""Get the X coordinate."""
return self._geometry.x
@property
def y(self):
"""Get the Y coordinate."""
return self._geometry.y
@property
def z(self):
"""Get the Z coordinate."""
return self._geometry.z
@property
def magnitude(self):
"""Get the magnitude of the vector."""
return self._geometry.magnitude
[docs]
def normalize(self):
"""Ensure that this DisplayVector3D is a unit vector (magnitude=1)."""
self._geometry = self._geometry.normalize()
[docs]
def reverse(self):
"""Reverse this DisplayVector3D."""
self._geometry = self._geometry.__neg__()
[docs]
def dot(self, other):
"""Get the dot product of this vector with another DisplayVector3D."""
return self.geometry.dot(other.geometry)
[docs]
def cross(self, other):
"""Get the cross product of this vector and another DisplayVector3D."""
return self.geometry.cross(other.geometry)
[docs]
def angle(self, other):
"""Get the angle between this vector and another DisplayVector3D in degrees."""
return math.degrees(self.geometry.angle(other.geometry))
[docs]
def rotate(self, axis, angle):
"""Rotate this geometry by a certain angle around an axis and origin.
Args:
axis: A ladybug_geometry Vector3D axis representing the axis of rotation.
angle: An angle for rotation in degrees.
"""
self._geometry = self.geometry.rotate(axis, math.radians(angle))
[docs]
def rotate_xy(self, angle):
"""Rotate this geometry counterclockwise in the world XY plane by an angle.
Args:
angle: An angle in degrees.
"""
self._geometry = self.geometry.rotate_xy(math.radians(angle))
[docs]
def reflect(self, normal):
"""Reflect this geometry across a plane with the input normal vector.
Args:
normal: A Vector3D representing the normal vector for the plane across
which the vector will be reflected. THIS VECTOR MUST BE NORMALIZED.
"""
self._geometry = self.geometry.reflect(normal)
[docs]
def to_dict(self):
"""Return DisplayVector3D as a dictionary.
"""
base = {'type': 'DisplayVector3D'}
base['geometry'] = self._geometry.to_dict()
base['color'] = self.color.to_dict()
if self.user_data is not None:
base['user_data'] = self.user_data
return base
def __copy__(self):
new_g = DisplayVector3D(self.geometry, self.color)
new_g._user_data = None if self.user_data is None else self.user_data.copy()
return new_g
def __getitem__(self, key):
return (self.x, self.y, self.z)[key]
def __iter__(self):
return iter((self.x, self.y, self.z))
def __mul__(self, other):
assert type(other) in (int, float), 'Cannot multiply types {} and {}'.format(
self.__class__.__name__, type(other))
new_g = DisplayVector3D(self.geometry * other, self.color)
new_g._user_data = None if self.user_data is None else self.user_data.copy()
return new_g
def __div__(self, other):
assert type(other) in (int, float), 'Cannot divide types {} and {}'.format(
self.__class__.__name__, type(other))
new_g = DisplayVector3D(self.geometry / other, self.color)
new_g._user_data = None if self.user_data is None else self.user_data.copy()
return new_g
def __repr__(self):
return 'DisplayVector3D: {}'.format(self.geometry)