|
1 | 1 | from nose.tools import assert_raises
|
2 |
| -from mpl_toolkits.mplot3d import Axes3D, axes3d |
| 2 | +from mpl_toolkits.mplot3d import Axes3D, axes3d, proj3d |
3 | 3 | from matplotlib import cm
|
4 | 4 | from matplotlib.testing.decorators import image_comparison, cleanup
|
| 5 | +from matplotlib.collections import LineCollection |
| 6 | +from matplotlib.patches import Circle |
5 | 7 | import matplotlib.pyplot as plt
|
6 | 8 | import numpy as np
|
7 | 9 |
|
@@ -340,7 +342,120 @@ def test_plotsurface_1d_raises():
|
340 | 342 | fig = plt.figure(figsize=(14,6))
|
341 | 343 | ax = fig.add_subplot(1, 2, 1, projection='3d')
|
342 | 344 | assert_raises(ValueError, ax.plot_surface, X, Y, z)
|
343 |
| - |
| 345 | + |
| 346 | + |
| 347 | +def _test_proj_make_M(): |
| 348 | + # eye point |
| 349 | + E = np.array([1000, -1000, 2000]) |
| 350 | + R = np.array([100, 100, 100]) |
| 351 | + V = np.array([0, 0, 1]) |
| 352 | + viewM = proj3d.view_transformation(E, R, V) |
| 353 | + perspM = proj3d.persp_transformation(100, -100) |
| 354 | + M = np.dot(perspM, viewM) |
| 355 | + return M |
| 356 | + |
| 357 | + |
| 358 | +def test_proj_transform(): |
| 359 | + M = _test_proj_make_M() |
| 360 | + |
| 361 | + xs = np.array([0, 1, 1, 0, 0, 0, 1, 1, 0, 0]) * 300.0 |
| 362 | + ys = np.array([0, 0, 1, 1, 0, 0, 0, 1, 1, 0]) * 300.0 |
| 363 | + zs = np.array([0, 0, 0, 0, 0, 1, 1, 1, 1, 1]) * 300.0 |
| 364 | + |
| 365 | + txs, tys, tzs = proj3d.proj_transform(xs, ys, zs, M) |
| 366 | + ixs, iys, izs = proj3d.inv_transform(txs, tys, tzs, M) |
| 367 | + |
| 368 | + np.testing.assert_almost_equal(ixs, xs) |
| 369 | + np.testing.assert_almost_equal(iys, ys) |
| 370 | + np.testing.assert_almost_equal(izs, zs) |
| 371 | + |
| 372 | + |
| 373 | +def _test_proj_draw_axes(M, s=1, *args, **kwargs): |
| 374 | + xs = [0, s, 0, 0] |
| 375 | + ys = [0, 0, s, 0] |
| 376 | + zs = [0, 0, 0, s] |
| 377 | + txs, tys, tzs = proj3d.proj_transform(xs, ys, zs, M) |
| 378 | + o, ax, ay, az = zip(txs, tys) |
| 379 | + lines = [(o, ax), (o, ay), (o, az)] |
| 380 | + |
| 381 | + fig, ax = plt.subplots(*args, **kwargs) |
| 382 | + linec = LineCollection(lines) |
| 383 | + ax.add_collection(linec) |
| 384 | + for x, y, t in zip(txs, tys, ['o', 'x', 'y', 'z']): |
| 385 | + ax.text(x, y, t) |
| 386 | + |
| 387 | + return fig, ax |
| 388 | + |
| 389 | + |
| 390 | +@image_comparison(baseline_images=['proj3d_axes_cube'], extensions=['png'], |
| 391 | + remove_text=True, style='default') |
| 392 | +def test_proj_axes_cube(): |
| 393 | + M = _test_proj_make_M() |
| 394 | + |
| 395 | + ts = '0 1 2 3 0 4 5 6 7 4'.split() |
| 396 | + xs = np.array([0, 1, 1, 0, 0, 0, 1, 1, 0, 0]) * 300.0 |
| 397 | + ys = np.array([0, 0, 1, 1, 0, 0, 0, 1, 1, 0]) * 300.0 |
| 398 | + zs = np.array([0, 0, 0, 0, 0, 1, 1, 1, 1, 1]) * 300.0 |
| 399 | + |
| 400 | + txs, tys, tzs = proj3d.proj_transform(xs, ys, zs, M) |
| 401 | + |
| 402 | + fig, ax = _test_proj_draw_axes(M, s=400) |
| 403 | + |
| 404 | + ax.scatter(txs, tys, c=tzs) |
| 405 | + ax.plot(txs, tys, c='r') |
| 406 | + for x, y, t in zip(txs, tys, ts): |
| 407 | + ax.text(x, y, t) |
| 408 | + |
| 409 | + ax.set_xlim(-0.2, 0.2) |
| 410 | + ax.set_ylim(-0.2, 0.2) |
| 411 | + |
| 412 | + |
| 413 | +def test_rot(): |
| 414 | + V = [1, 0, 0, 1] |
| 415 | + rotated_V = proj3d.rot_x(V, np.pi / 6) |
| 416 | + np.testing.assert_allclose(rotated_V, [1, 0, 0, 1]) |
| 417 | + |
| 418 | + V = [0, 1, 0, 1] |
| 419 | + rotated_V = proj3d.rot_x(V, np.pi / 6) |
| 420 | + np.testing.assert_allclose(rotated_V, [0, np.sqrt(3) / 2, 0.5, 1]) |
| 421 | + |
| 422 | + |
| 423 | +def test_world(): |
| 424 | + xmin, xmax = 100, 120 |
| 425 | + ymin, ymax = -100, 100 |
| 426 | + zmin, zmax = 0.1, 0.2 |
| 427 | + M = proj3d.world_transformation(xmin, xmax, ymin, ymax, zmin, zmax) |
| 428 | + np.testing.assert_allclose(M, |
| 429 | + [[5e-2, 0, 0, -5], |
| 430 | + [0, 5e-3, 0, 5e-1], |
| 431 | + [0, 0, 1e1, -1], |
| 432 | + [0, 0, 0, 1]]) |
| 433 | + |
| 434 | + |
| 435 | +@image_comparison(baseline_images=['proj3d_lines_dists'], extensions=['png'], |
| 436 | + remove_text=True, style='default') |
| 437 | +def test_lines_dists(): |
| 438 | + fig, ax = plt.subplots(figsize=(4, 6), subplot_kw=dict(aspect='equal')) |
| 439 | + |
| 440 | + xs = (0, 30) |
| 441 | + ys = (20, 150) |
| 442 | + ax.plot(xs, ys) |
| 443 | + p0, p1 = zip(xs, ys) |
| 444 | + |
| 445 | + xs = (0, 0, 20, 30) |
| 446 | + ys = (100, 150, 30, 200) |
| 447 | + ax.scatter(xs, ys) |
| 448 | + |
| 449 | + dist = proj3d.line2d_seg_dist(p0, p1, (xs[0], ys[0])) |
| 450 | + dist = proj3d.line2d_seg_dist(p0, p1, np.array((xs, ys))) |
| 451 | + for x, y, d in zip(xs, ys, dist): |
| 452 | + c = Circle((x, y), d, fill=0) |
| 453 | + ax.add_patch(c) |
| 454 | + |
| 455 | + ax.set_xlim(-50, 150) |
| 456 | + ax.set_ylim(0, 300) |
| 457 | + |
| 458 | + |
344 | 459 | if __name__ == '__main__':
|
345 | 460 | import nose
|
346 | 461 | nose.runmodule(argv=['-s', '--with-doctest'], exit=False)
|
0 commit comments