Shapes in depth — Shape4D 0.08 documentation

# Shapes in depth

VisualShapes is the visual version of shape functions, including necessary operations on shapes. It encapsualtes parts of matplotlib for the purpose of instant visualization of shapes just created. In a situation where the visualization is not necessary, it is efficient for one to use the low level shape functions themselves.

Shape functions aim to simplify the creation of polygons with vertices in either 3D or 2D space, a process that is prone to error in practice. Here, we choose the yz plane as the working plane, and design some descriptions for 2D shape dimensions of wall/roofs that are commonly seen in building or/and solar panels of electricity or thermal fluids. As soon as they have been set in the working plane (2D), defined shapes can be moved to their specific 3D positions by using a helper function move().

Note

All definitions are included in Shape4D.Shapes, and first of all, one has to import it as shown below.

    >>> import Shape4D.Shapes as shape

## Shapes

At first, the relation between dimensions and the vertices of shapes are shown as indicated below,

    W, H = 1.0, 0.5
    shape.rectangle(W,H)
    >>>  array([[0. , 0. , 0. ],
               [0. , 1. , 0. ],
               [0. , 1. , 0.5],
               [0. , 0. , 0.5]])

    A = 0.2
    shape.triangle(W,H,A)
    >>>  array([[0. , 0. , 0. ],
                [0. , 1. , 0. ],
                [0. , 0.2, 0.5]])

    B,C = 0.5, 0.2
    shape.fourSided(W,H,A,B,C)
    >>>  array([[0. , 0. , 0. ],
                [0. , 1. , 0. ],
                [0. , 0.4, 0.5],
                [0. , 0.2, 0.5]])

    D = 0.5
    shape.fiveSided(W,H,A,B,C,D)
    >>>  array([[0. , 0. , 0. ],
                [0. , 1. , 0. ],
                [0. , 1.2, 0.5],
                [0. , 0.7, 0.5],
                [0. , 0.2, 0.5]])

As shown in these figures, the dimensions of these shapes produce their own vertices in counter-clockwise.loops.

## A complex shape

For windows/doors/roofs or other walls/panels with opennings, we design a more complex shape.

    W,H,A,B,C,D = 1.0,0.5, 0.4, 0.2, 0.2, 0.3
    shape.rectangleWithHole(W,H,A,B,C,D)
    >>>  array([[0. , 0. , 0. ],
                [0. , 1. , 0. ],
                [0. , 1. , 0.5],
                [0. , 0.3, 0.5],
                [0. , 0.3, 0.4],
                [0. , 0.7, 0.4],
                [0. , 0.7, 0.2],
                [0. , 0.3, 0.2],
                [0. , 0.3, 0.5],
                [0. , 0. , 0.5]])

rectangleWithHole(W,H,A,B,C,D) will not always return 10 vertices, and for the following special cases, it will return vertices as few as possible.

The following code is for verification of the design.

    import numpy as np
    from Shape4D.Shapes import *

    def shape2D(W,H,A,B,C,D):
        ret = rectangleWithHole(W,H,A,B,C,D)
        x,y,z = zip(*ret)
        return np.array([y,z])

    %matplotlib notebook
    import matplotlib.pyplot as plt

    fig, axs = plt.subplots(3,3)

    W,H,A,B,C,D = 3,2.5,1.5,1.0,0.7,0.0
    C = H - B
    xs,ys = shape2D(W,H,A,B,C,D)
    axs[0,0].set_aspect('equal', 'datalim')
    axs[0,0].fill(xs, ys, alpha=0.5, fc='r', ec='none')
    axs[0,0].set_axis_off()
    label = f"{xs.size} vertices"
    axs[0,0].annotate(label, (0.1, 0.5), xycoords='axes fraction', va='center')

    W,H,A,B,C,D = 3,2.5,1.5,1.0,0.7,0.0
    C = H - B
    D = 0.8
    xs,ys = shape2D(W,H,A,B,C,D)
    axs[0,1].set_aspect('equal', 'datalim')
    axs[0,1].fill(xs, ys, alpha=0.5, fc='r', ec='none')
    axs[0,1].set_axis_off()
    label = f"{xs.size} vertices"
    axs[0,1].annotate(label, (0.1, 0.5), xycoords='axes fraction', va='center')

    W,H,A,B,C,D = 3,2.5,1.5,1.0,0.7,0.0
    C = H - B
    D = W - A
    xs,ys = shape2D(W,H,A,B,C,D)
    axs[0,2].set_aspect('equal', 'datalim')
    axs[0,2].fill(xs, ys, alpha=0.5, fc='r', ec='none')
    axs[0,2].set_axis_off()
    label = f"{xs.size} vertices"
    axs[0,2].annotate(label, (0.1, 0.5), xycoords='axes fraction', va='center')

    W,H,A,B,C,D = 3,2.5,1.5,1.0,0.7,0.0
    xs,ys = shape2D(W,H,A,B,C,D)
    axs[1,0].set_aspect('equal', 'datalim')
    axs[1,0].fill(xs, ys, alpha=0.5, fc='r', ec='none')
    axs[1,0].set_axis_off()
    label = f"{xs.size} vertices"
    axs[1,0].annotate(label, (0.1, 0.5), xycoords='axes fraction', va='center')

    W,H,A,B,C,D = 3,2.5,1.5,1.0,0.7,0.8
    xs,ys = shape2D(W,H,A,B,C,D)
    axs[1,1].set_aspect('equal', 'datalim')
    axs[1,1].fill(xs, ys, alpha=0.5, fc='r', ec='none')
    axs[1,1].set_axis_off()
    label = f"{xs.size} vertices"
    axs[1,1].annotate(label, (0.1, 0.5), xycoords='axes fraction', va='center')

    W,H,A,B,C,D = 3,2.5,1.5,1.0,0.7,0.8
    D = W - A
    xs,ys = shape2D(W,H,A,B,C,D)
    axs[1,2].set_aspect('equal', 'datalim')
    axs[1,2].fill(xs, ys, alpha=0.5, fc='r', ec='none')
    axs[1,2].set_axis_off()
    label = f"{xs.size} vertices"
    axs[1,2].annotate(label, (0.1, 0.5), xycoords='axes fraction', va='center')

    W,H,A,B,C,D = 3,2.5,1.5,1.0,0.7,0.8
    C = 0
    D = 0
    xs,ys = shape2D(W,H,A,B,C,D)
    axs[2,0].set_aspect('equal', 'datalim')
    axs[2,0].fill(xs, ys, alpha=0.5, fc='r', ec='none')
    axs[2,0].set_axis_off()
    label = f"{xs.size} vertices"
    axs[2,0].annotate(label, (0.1, 0.5), xycoords='axes fraction', va='center')

    W,H,A,B,C,D = 3,2.5,1.5,1.0,0.7,0.8
    C = 0
    xs,ys = shape2D(W,H,A,B,C,D)
    axs[2,1].set_aspect('equal', 'datalim')
    axs[2,1].fill(xs, ys, alpha=0.5, fc='r', ec='none')
    axs[2,1].set_axis_off()
    label = f"{xs.size} vertices"
    axs[2,1].annotate(label, (0.1, 0.5), xycoords='axes fraction', va='center')

    W,H,A,B,C,D = 3,2.5,1.5,1.0,0.7,0.8
    C = 0
    D = W - A
    xs,ys = shape2D(W,H,A,B,C,D)
    axs[2,2].set_aspect('equal', 'datalim')
    axs[2,2].fill(xs, ys, alpha=0.5, fc='r', ec='none')
    axs[2,2].set_axis_off()
    label = f"{xs.size} vertices"
    axs[2,2].annotate(label, (0.1, 0.5), xycoords='axes fraction', va='center')

    plt.show()

## Transformation to 3D position

After all 2D shapes have been defined with their origin at (0,0,0), one can transform a shape to its 3D position by rotating and translating. The rotating angles and the new 3D position of origin are designated as follow.

Accordingly, the transformation matrix is

## Examples

Example 1

A cubic box

    import numpy as np
    from Shape4D.Shapes import *

    def box3D(L,W,H):
        rectLW = rectangle(L,W)
        rectWH = rectangle(W,H)
        rectLH = rectangle(L,H)

        bottom = move(shape = rectLW,to = (0,0,0), by = (0,-90) )
        top    = move(shape = rectLW,to = (W,0,H), by = (0, 90) )

        front = move(shape = rectLH,to = (W,0,0), by = (0,0) )
        back  = move(shape = rectLH,to = (0,L,0), by = (180,0) )

        left  = move(shape = rectWH,to = (0,0,0),by = (-90, 0))
        right = move(shape = rectWH,to = (W,L,0),by = ( 90, 0))

        polygons = np.array([front,right,back,left,top,bottom])

        return polygons

    %matplotlib notebook
    from mpl_toolkits.mplot3d import Axes3D
    from mpl_toolkits.mplot3d.art3d import Poly3DCollection
    import matplotlib.pyplot as plt

    polygons = box3D(1,0.7,0.5)

    fig = plt.figure()
    ax = Axes3D(fig)
    box = Poly3DCollection(polygons)
    box.set_facecolor('brown')
    box.set_edgecolor('yellow')
    ax.add_collection3d(box)
    ax.axis('off')
    plt.show()

Example 2

A simple house

    import numpy as np
    from Shape4D.Shapes import *

    def house3D(L,W,H,A,B,C,D):
        rectLW = rectangle(L,W)
        rectWH = rectangle(W,H)
        rectLH = rectangle(L,H)
        rectLH_window = rectangleWithHole(L,H,A,B,C,D)

        bottom = move(shape = rectLW,to = (0,0,0), by = (0,-90) )
        top    = move(shape = rectLW,to = (W,0,H), by = (0, 90) )

        front = move(shape = rectLH_window,to = (W,0,0), by = (0,0) )
        back  = move(shape = rectLH,to = (0,L,0), by = (180,0) )

        left  = move(shape = rectWH,to = (0,0,0),by = (-90, 0))
        right = move(shape = rectWH,to = (W,L,0),by = ( 90, 0))

        polygons = np.array([front,right,back,left,top,bottom])

        return polygons

    %matplotlib notebook
    from mpl_toolkits.mplot3d import Axes3D
    from mpl_toolkits.mplot3d.art3d import Poly3DCollection
    import matplotlib.pyplot as plt

    L,W,H,A,B,C,D = 3,3,2.5,1.5,1.0,1.0,0.7
    box = Poly3DCollection(house3D(L,W,H,A,B,C,D))

    fig = plt.figure()
    ax = Axes3D(fig)
    box.set_facecolor('brown')
    box.set_edgecolor('yellow')
    ax.add_collection3d(box)
    ax.axis('off')
    plt.show()