In [1]:
# this line is needed for the web notebook only
%matplotlib inline
CIVL4250 Numerical Methods in Engineering
Dr Dorival Pedroso
Code available on https://github.com/cpmech/CIVL4250py
A vertex can be uniquely defined by simply recording its Cartesian coordinates x
and y
. Nonetheless, for the sake of illustration and classification, we will also give an identification number (id) and a tag to each vertex.
The id is useful to identify vertices without the need for comparing coordinates.
The tag is useful to classify vertices; i.e. to group vertices. For example, tagging all vertices located along a given line defines a group of vertices. We will use negative integers as tags because this helps to differentiate between ids and tags. By using negative numbers, we can also say that 0 means that the vertex is not tagged.
In this way, one vertex is defined by a list with 4 items as follows
In [2]:
vertex_A = [0, -100, 0.5, 0.5] # id, tag, x, y
where the 4 items are the id, the tag (a negative number or zero), followed by the x and y coordinates.
For example, suppose another vertex in the same group of vertex_A
is to be defined, then
In [3]:
vertex_B = [1, -100, 0.5, 1.0]
If a set of vertices is needed, this can be easily defined by means of
In [4]:
vertices = [vertex_A, vertex_B]
or
In [5]:
vertices = [[0, -100, 0.5, 0.5],
[1, -100, 0.5, 1.0]]
which directly creates a list of lists with all vertices.
In [6]:
# id tag x y
V = [[ 0, -100, 0.0, 0.0], # vert # 0
[ 1, -100, 1.5, 0.0], # vert # 1
[ 2, -200, 1.5, 2.5], # vert # 2
[ 3, -300, 0.0, 2.5]] # vert # 3
Then, a triangle can be defined by just selecting 3 vertices in the list above. Nonetheless, an id and a tag will also be given to each triangle.
Therefore, one triangle is specified by a list with 3 items as follows
In [7]:
triangle_T = [0, -1, [0, 1, 2]] # id, tag, list_of_vertices_ids
where:
V
.Another triangle could be defined as follows
In [8]:
triangle_S = [1, -2, [0, 2, 3]]
and a list of triangles can be written as
In [9]:
C = [triangle_T, triangle_S]
or
In [10]:
C = [[0, -1, [0, 1, 2]],
[1, -2, [0, 2, 3]]]
where the the variable C
is used instead of triangles
just for convenience. C
means Cells.
This can be easily accomplished with
In [11]:
print '=' * 58
print '%5s%5s (%6s,%6s) (%6s,%6s) (%6s,%6s)' % ('id', 'tag', 'x0','y0', 'x1','y1', 'x2','y2')
print '-' * 58
for c in C:
id = c[0] # triangle's ID
tag = c[1] # triangle's Tag
n0 = c[2][0] # first node defining this triangle
n1 = c[2][1] # second node defining this triangle
n2 = c[2][2] # third node defining this triangle
P = V[n0] # first vertex (extracting from previous V list)
Q = V[n1] # second vertex
R = V[n2] # third vertex
x0, y0 = P[2], P[3] # coordinates of first vertex
x1, y1 = Q[2], Q[3] # coordinates of second vertex
x2, y2 = R[2], R[3] # coordinates of third vertex
print '%5s%5s (%6.2f,%6.2f) (%6.2f,%6.2f) (%6.2f,%6.2f)' % (id, tag, x0,y0, x1,y1, x2,y2)
print '=' * 58
Polygons are drawn with matplotlib
using the path
and patches
commands. See e.g. Matplotlib Shapes.
path
defines a polygon by means of an analogy to drawing by hand. First, the pen is moved (MOVETO
) to the first point, then it is moved along a line to the next point (LINETO
). Finally, the patch (the polygon) is created by closing the set of lines (CLOSEPOLY
).
For instance, the patch
defining one triangle is given by
In [12]:
import matplotlib.pyplot as plt
import matplotlib.path as mph
import matplotlib.patches as mpc
# 1: define the path data corresponding to the geometry of one Triangle => like drawing by hand
dum = 0 # dummy variable
path_data = [ [mph.Path.MOVETO, [0.0, 0.0] ],
[mph.Path.LINETO, [1.5, 0.0] ],
[mph.Path.LINETO, [1.5, 2.5] ],
[mph.Path.CLOSEPOLY, [dum, dum] ] ]
# 2: create the path structure from the path data
blackbox = zip(*path_data) # don't worry about this line
path = mph.Path(blackbox[1], blackbox[0])
# 3: create the shape structure with colors and lines for MatPlotLib
shape = mpc.PathPatch(path, facecolor='lightyellow', edgecolor='black')
# 4: grab the current axis (if none, a new figure is created) and then add the shape to it
plt.gca().add_patch(shape)
plt.axis('equal');
Now, a function can be created encapsulating the previous commands for the sake of convenience. In this way, the function could be called within a loop and thus many triangles could be drawn.
This function can also perform the writing of triangles' label (=ids) as requested.
A function to draw one triangle is thus defined as follows
In [13]:
def DrawTriangle(V, T, color='#e9eefe'):
# 0: collect triangles' data
id, tag = T[0], T[1]
n0, n1, n2 = T[2][0], T[2][1], T[2][2]
P, Q, R = V[n0], V[n1], V[n2]
# 1: define the path data corresponding to one Triangle
path_data = [ [mph.Path.MOVETO, P[2:4] ],
[mph.Path.LINETO, Q[2:4] ],
[mph.Path.LINETO, R[2:4] ],
[mph.Path.CLOSEPOLY, [0,0] ] ]
# 2: create the path structure from the path data
blackbox = zip(*path_data)
path = mph.Path(blackbox[1], blackbox[0])
# 3: create the shape structure with colors and lines for MatPlotLib
shape = mpc.PathPatch(path, facecolor=color, edgecolor='black')
# 4: grab the current axis (if none, a new figure is created) and then add the shape to it
plt.gca().add_patch(shape)
# 5: write triangle's id
centre_x = (P[2] + Q[2] + R[2]) / 3.0
centre_y = (P[3] + Q[3] + R[3]) / 3.0
plt.text(centre_x, centre_y, '%d' % id, color='blue')
where V
is the list of vertices and T
is one triangle defined as in the previous sections.
The color string can be a name as defined here or a HTML color code; we will use the latter.
Also note that in Python, arguments followed by "= something" are optional and are already defined with default values. For instance, the color '#e9eefe' is already chosen.
The vertices ids can be easily written also using the text
command.
Now, all triangles in C
can be drawn as follows
In [14]:
# draw triangles
for c in C:
DrawTriangle(V, c)
# write vertices ids
for v in V:
plt.text(v[2], v[3], '%d' % v[0], color='red')
# use equal x-y scales
plt.axis('equal');