Init
This commit is contained in:
159
rotorpy/utils/axes3ds.py
Normal file
159
rotorpy/utils/axes3ds.py
Normal file
@@ -0,0 +1,159 @@
|
||||
"""
|
||||
This module provides Axes3Ds ("Axes3D Spatial"), a drop-in replacement for
|
||||
Axes3D which incorporates the improvements proposed by eric-wieser in matplotlib
|
||||
issue #8896.
|
||||
|
||||
The purpose is to reduce the distortion when projecting 3D scenes into the 2D
|
||||
image. For example, the projection of a sphere will be (closer to) a circle.
|
||||
"""
|
||||
|
||||
"""
|
||||
License agreement for matplotlib versions 1.3.0 and later
|
||||
=========================================================
|
||||
|
||||
1. This LICENSE AGREEMENT is between the Matplotlib Development Team
|
||||
("MDT"), and the Individual or Organization ("Licensee") accessing and
|
||||
otherwise using matplotlib software in source or binary form and its
|
||||
associated documentation.
|
||||
|
||||
2. Subject to the terms and conditions of this License Agreement, MDT
|
||||
hereby grants Licensee a nonexclusive, royalty-free, world-wide license
|
||||
to reproduce, analyze, test, perform and/or display publicly, prepare
|
||||
derivative works, distribute, and otherwise use matplotlib
|
||||
alone or in any derivative version, provided, however, that MDT's
|
||||
License Agreement and MDT's notice of copyright, i.e., "Copyright (c)
|
||||
2012- Matplotlib Development Team; All Rights Reserved" are retained in
|
||||
matplotlib alone or in any derivative version prepared by
|
||||
Licensee.
|
||||
|
||||
3. In the event Licensee prepares a derivative work that is based on or
|
||||
incorporates matplotlib or any part thereof, and wants to
|
||||
make the derivative work available to others as provided herein, then
|
||||
Licensee hereby agrees to include in any such work a brief summary of
|
||||
the changes made to matplotlib .
|
||||
|
||||
4. MDT is making matplotlib available to Licensee on an "AS
|
||||
IS" basis. MDT MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
||||
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, MDT MAKES NO AND
|
||||
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
||||
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF MATPLOTLIB
|
||||
WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
|
||||
|
||||
5. MDT SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF MATPLOTLIB
|
||||
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR
|
||||
LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING
|
||||
MATPLOTLIB , OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF
|
||||
THE POSSIBILITY THEREOF.
|
||||
|
||||
6. This License Agreement will automatically terminate upon a material
|
||||
breach of its terms and conditions.
|
||||
|
||||
7. Nothing in this License Agreement shall be deemed to create any
|
||||
relationship of agency, partnership, or joint venture between MDT and
|
||||
Licensee. This License Agreement does not grant permission to use MDT
|
||||
trademarks or trade name in a trademark sense to endorse or promote
|
||||
products or services of Licensee, or any third party.
|
||||
|
||||
8. By copying, installing or otherwise using matplotlib ,
|
||||
Licensee agrees to be bound by the terms and conditions of this License
|
||||
Agreement.
|
||||
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
|
||||
from mpl_toolkits.mplot3d import Axes3D
|
||||
from mpl_toolkits.mplot3d import proj3d
|
||||
|
||||
# Patch note: An update of the original implementation in proj3d.py.
|
||||
def world_transformation(xmin, xmax,
|
||||
ymin, ymax,
|
||||
zmin, zmax, pb_aspect=None):
|
||||
"""
|
||||
produce a matrix that scales homogenous coords in the specified ranges
|
||||
to [0, 1], or [0, pb_aspect[i]] if the plotbox aspect ratio is specified
|
||||
"""
|
||||
dx = xmax - xmin
|
||||
dy = ymax - ymin
|
||||
dz = zmax - zmin
|
||||
if pb_aspect is not None:
|
||||
ax, ay, az = pb_aspect
|
||||
dx /= ax
|
||||
dy /= ay
|
||||
dz /= az
|
||||
|
||||
return np.array([[1/dx, 0, 0, -xmin/dx],
|
||||
[0, 1/dy, 0, -ymin/dy],
|
||||
[0, 0, 1/dz, -zmin/dz],
|
||||
[0, 0, 0, 1]])
|
||||
|
||||
class Axes3Ds(Axes3D):
|
||||
"""
|
||||
Class Axes3Ds ("Axes3D Spatial") is a drop-in replacement for Axes3D which
|
||||
incorporates the improvements proposed by eric-wieser in matplotlib issue
|
||||
#8896.
|
||||
"""
|
||||
|
||||
# Patch note: A new function.
|
||||
def apply_aspect(self, position=None):
|
||||
if position is None:
|
||||
position = self.get_position(original=True)
|
||||
|
||||
# in the superclass, we would go through and actually deal with axis
|
||||
# scales and box/datalim. Those are all irrelevant - all we need to do
|
||||
# is make sure our coordinate system is square.
|
||||
figW, figH = self.get_figure().get_size_inches()
|
||||
fig_aspect = figH / figW
|
||||
box_aspect = 1
|
||||
pb = position.frozen()
|
||||
pb1 = pb.shrunk_to_aspect(box_aspect, pb, fig_aspect)
|
||||
self.set_position(pb1.anchored(self.get_anchor(), pb), 'active')
|
||||
|
||||
# Patch note: Overwritten to use the updated version of world_transformation
|
||||
# and the new pb_aspect value.
|
||||
def get_proj(self):
|
||||
"""
|
||||
Create the projection matrix from the current viewing position.
|
||||
elev stores the elevation angle in the z plane
|
||||
azim stores the azimuth angle in the x,y plane
|
||||
dist is the distance of the eye viewing point from the object
|
||||
point.
|
||||
"""
|
||||
# chosen for similarity with the initial view before gh-8896
|
||||
pb_aspect = np.array([4, 4, 3]) / 3.5
|
||||
|
||||
relev, razim = np.pi * self.elev/180, np.pi * self.azim/180
|
||||
|
||||
xmin, xmax = self.get_xlim3d()
|
||||
ymin, ymax = self.get_ylim3d()
|
||||
zmin, zmax = self.get_zlim3d()
|
||||
|
||||
# transform to uniform world coordinates 0-1.0,0-1.0,0-1.0
|
||||
worldM = world_transformation(xmin, xmax,
|
||||
ymin, ymax,
|
||||
zmin, zmax, pb_aspect=pb_aspect)
|
||||
|
||||
# look into the middle of the new coordinates
|
||||
R = pb_aspect / 2
|
||||
|
||||
xp = R[0] + np.cos(razim) * np.cos(relev) * self.dist
|
||||
yp = R[1] + np.sin(razim) * np.cos(relev) * self.dist
|
||||
zp = R[2] + np.sin(relev) * self.dist
|
||||
E = np.array((xp, yp, zp))
|
||||
|
||||
self.eye = E
|
||||
self.vvec = R - E
|
||||
self.vvec = self.vvec / np.linalg.norm(self.vvec)
|
||||
|
||||
if abs(relev) > np.pi/2:
|
||||
# upside down
|
||||
V = np.array((0, 0, -1))
|
||||
else:
|
||||
V = np.array((0, 0, 1))
|
||||
zfront, zback = -self.dist, self.dist
|
||||
|
||||
viewM = proj3d.view_transformation(E, R, V)
|
||||
projM = self._projection(zfront, zback)
|
||||
M0 = np.dot(viewM, worldM)
|
||||
M = np.dot(projM, M0)
|
||||
return M
|
||||
Reference in New Issue
Block a user