Predefined shapes — Shape4D 0.08 documentation

# Predefined shapes

What we use vertices to define polygons, either 3D or 2D, is prone to error. Here, we design some common shapes for wall/roofs in building or/and for solar panels for electricity or thermal fluids, which can be initiated extactly and conveniently by dimensions other than vertices. As stated above, the shapes are described in 2D space and can be moved to their real 3D positions by using function move() in Shape4D.

Note

All 2D shapes are defined in Shapes, and one has to import it as shown below before initiating any of them.

    >>> import Shape4D.Shapes as shape

## 2D shapes

At first, we define the simple shapes by dimensions, and their vertices can be calculated as indicated,

    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 2D 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

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()