source: lmdz_wrf/trunk/tools/geometry_tools.py @ 2454

Last change on this file since 2454 was 2454, checked in by lfita, 6 years ago

Adding:

  • `p_reg_polygon': Function to provide a regular polygon of Nv vertices
  • `p_reg_star': Function to provide a regular star of Nv vertices
File size: 27.6 KB
Line 
1# Python tools to manage netCDF files.
2# L. Fita, CIMA. Mrch 2019
3# More information at: http://www.xn--llusfb-5va.cat/python/PyNCplot
4#
5# pyNCplot and its component geometry_tools.py comes with ABSOLUTELY NO WARRANTY.
6# This work is licendes under a Creative Commons
7#   Attribution-ShareAlike 4.0 International License (http://creativecommons.org/licenses/by-sa/4.0)
8#
9## Script for geometry calculations and operations as well as definition of different
10###    standard objects and shapes
11
12import numpy as np
13import matplotlib as mpl
14from mpl_toolkits.mplot3d import Axes3D
15import matplotlib.pyplot as plt
16import os
17
18errormsg = 'ERROR -- error -- ERROR -- error'
19infmsg = 'INFORMATION -- information -- INFORMATION -- information'
20
21####### Contents:
22# deg_deci: Function to pass from degrees [deg, minute, sec] to decimal angles [rad]
23# dist_points: Function to provide the distance between two points
24# max_coords_poly: Function to provide the extremes of the coordinates of a polygon
25# mirror_polygon: Function to reflex a polygon for a given axis
26# position_sphere: Function to tranform fom a point in lon, lat deg coordinates to
27#   cartesian coordinates over an sphere
28# read_join_poly: Function to read an ASCII file with the combination of polygons
29# rotate_2D: Function to rotate a vector by a certain angle in the plain
30# rotate_polygon_2D: Function to rotate 2D plain the vertices of a polygon
31# rotate_line2D: Function to rotate a line given by 2 pairs of x,y coordinates by a
32#   certain angle in the plain
33# rotate_lines2D: Function to rotate multiple lines given by mulitple pars of x,y
34#   coordinates by a certain angle in the plain
35# spheric_line: Function to transform a series of locations in lon, lat coordinates
36#   to x,y,z over an 3D spaceFunction to provide coordinates of a line  on a 3D space
37# write_join_poly: Function to write an ASCII file with the combination of polygons
38
39## Shapes/objects
40# circ_sec: Function union of point A and B by a section of a circle
41# ellipse_polar: Function to determine an ellipse from its center and polar coordinates
42# p_circle: Function to get a polygon of a circle
43# p_reg_polygon: Function to provide a regular polygon of Nv vertices
44# p_reg_star: Function to provide a regular star of Nv vertices
45# p_square: Function to get a polygon square
46# p_spiral: Function to provide a polygon of an Archimedean spiral
47# p_triangle: Function to provide the polygon of a triangle from its 3 vertices
48# surface_sphere: Function to provide an sphere as matrix of x,y,z coordinates
49
50## Plotting
51# plot_sphere: Function to plot an sphere and determine which standard lines will be
52#   also drawn
53
54def deg_deci(angle):
55    """ Function to pass from degrees [deg, minute, sec] to decimal angles [rad]
56      angle: list of [deg, minute, sec] to pass
57    >>> deg_deci([41., 58., 34.])
58    0.732621346072
59    """
60    fname = 'deg_deci'
61
62    deg = np.abs(angle[0]) + np.abs(angle[1])/60. + np.abs(angle[2])/3600.
63
64    if angle[0] < 0.: deg = -deg*np.pi/180.
65    else: deg = deg*np.pi/180.
66
67    return deg
68
69def position_sphere(radii, alpha, beta):
70    """ Function to tranform fom a point in lon, lat deg coordinates to cartesian 
71          coordinates over an sphere
72      radii: radii of the sphere
73      alpha: longitude of the point
74      beta: latitude of the point
75    >>> position_sphere(10., 30., 45.)
76    (0.81031678432964027, -5.1903473778327376, 8.5090352453411846
77    """
78    fname = 'position_sphere'
79
80    xpt = radii*np.cos(beta)*np.cos(alpha)
81    ypt = radii*np.cos(beta)*np.sin(alpha)
82    zpt = radii*np.sin(beta)
83
84    return xpt, ypt, zpt
85
86def spheric_line(radii,lon,lat):
87    """ Function to transform a series of locations in lon, lat coordinates to x,y,z
88          over an 3D space
89      radii: radius of the sphere
90      lon: array of angles along longitudes
91      lat: array of angles along latitudes
92    """
93    fname = 'spheric_line'
94
95    Lint = lon.shape[0]
96    coords = np.zeros((Lint,3), dtype=np.float)
97
98    for iv in range(Lint):
99        coords[iv,:] = position_sphere(radii, lon[iv], lat[iv])
100
101    return coords
102
103def rotate_2D(vector, angle):
104    """ Function to rotate a vector by a certain angle in the plain
105      vector= vector to rotate [y, x]
106      angle= angle to rotate [rad]
107    >>> rotate_2D(np.array([1.,0.]), np.pi/4.)
108    [ 0.70710678 -0.70710678]
109    """
110    fname = 'rotate_2D'
111
112    rotmat = np.zeros((2,2), dtype=np.float)
113
114    rotmat[0,0] = np.cos(angle)
115    rotmat[0,1] = -np.sin(angle)
116    rotmat[1,0] = np.sin(angle)
117    rotmat[1,1] = np.cos(angle)
118
119    rotvector = np.zeros((2), dtype=np.float)
120
121    vecv = np.zeros((2), dtype=np.float)
122
123    # Unifying vector
124    modvec = vector[0]**2+vector[1]**2
125    if modvec != 0: 
126        vecv[0] = vector[1]/modvec
127        vecv[1] = vector[0]/modvec
128
129        rotvec = np.matmul(rotmat, vecv)
130        rotvec = np.where(np.abs(rotvec) < 1.e-7, 0., rotvec)
131
132        rotvector[0] = rotvec[1]*modvec
133        rotvector[1] = rotvec[0]*modvec
134
135    return rotvector
136
137def rotate_polygon_2D(vectors, angle):
138    """ Function to rotate 2D plain the vertices of a polygon
139      line= matrix of vectors to rotate
140      angle= angle to rotate [rad]
141    >>> square = np.zeros((4,2), dtype=np.float)
142    >>> square[0,:] = [-0.5,-0.5]
143    >>> square[1,:] = [0.5,-0.5]
144    >>> square[2,:] = [0.5,0.5]
145    >>> square[3,:] = [-0.5,0.5]
146    >>> rotate_polygon_2D(square, np.pi/4.)
147    [[-0.70710678  0.        ]
148     [ 0.         -0.70710678]
149     [ 0.70710678  0.        ]
150     [ 0.          0.70710678]]
151    """
152    fname = 'rotate_polygon_2D'
153
154    rotvecs = np.zeros(vectors.shape, dtype=np.float)
155
156    Nvecs = vectors.shape[0]
157    for iv in range(Nvecs):
158        rotvecs[iv,:] = rotate_2D(vectors[iv,:], angle)
159
160    return rotvecs
161
162def rotate_line2D(line, angle):
163    """ Function to rotate a line given by 2 pairs of x,y coordinates by a certain
164          angle in the plain
165      line= line to rotate as couple of points [[y0,x0], [y1,x1]]
166      angle= angle to rotate [rad]
167    >>> rotate_line2D(np.array([[0.,0.], [1.,0.]]), np.pi/4.)
168    [[ 0.          0.        ]
169     [0.70710678  -0.70710678]]
170    """
171    fname = 'rotate_2D'
172
173    rotline = np.zeros((2,2), dtype=np.float)
174    rotline[0,:] = rotate_2D(line[0,:], angle)
175    rotline[1,:] = rotate_2D(line[1,:], angle)
176
177    return rotline
178
179def rotate_lines2D(lines, angle):
180    """ Function to rotate multiple lines given by mulitple pars of x,y coordinates 
181          by a certain angle in the plain
182      line= matrix of N couples of points [N, [y0,x0], [y1,x1]]
183      angle= angle to rotate [rad]
184    >>> square = np.zeros((4,2,2), dtype=np.float)
185    >>> square[0,0,:] = [-0.5,-0.5]
186    >>> square[0,1,:] = [0.5,-0.5]
187    >>> square[1,0,:] = [0.5,-0.5]
188    >>> square[1,1,:] = [0.5,0.5]
189    >>> square[2,0,:] = [0.5,0.5]
190    >>> square[2,1,:] = [-0.5,0.5]
191    >>> square[3,0,:] = [-0.5,0.5]
192    >>> square[3,1,:] = [-0.5,-0.5]
193    >>> rotate_lines2D(square, np.pi/4.)
194    [[[-0.70710678  0.        ]
195      [ 0.         -0.70710678]]
196
197     [[ 0.         -0.70710678]
198      [ 0.70710678  0.        ]]
199
200     [[ 0.70710678  0.        ]
201      [ 0.          0.70710678]]
202
203     [[ 0.          0.70710678]
204      [-0.70710678  0.        ]]]
205    """
206    fname = 'rotate_lines2D'
207
208    rotlines = np.zeros(lines.shape, dtype=np.float)
209
210    Nlines = lines.shape[0]
211    for il in range(Nlines):
212        line = np.zeros((2,2), dtype=np.float)
213        line[0,:] = lines[il,0,:]
214        line[1,:] = lines[il,1,:]
215
216        rotlines[il,:,:] = rotate_line2D(line, angle)
217
218    return rotlines
219
220def dist_points(ptA, ptB):
221    """ Function to provide the distance between two points
222      ptA: coordinates of the point A [yA, xA]
223      ptB: coordinates of the point B [yB, xB]
224    >>> dist_points([1.,1.], [-1.,-1.])
225    2.82842712475
226    """
227    fname = 'dist_points'
228
229    dist = np.sqrt( (ptA[0]-ptB[0])**2 + (ptA[1]-ptB[1])**2)
230
231    return dist
232
233def max_coords_poly(polygon):
234    """ Function to provide the extremes of the coordinates of a polygon
235      polygon: coordinates [Nvertexs, 2] of a polygon
236    >>> square = np.zeros((4,2), dtype=np.float)
237    >>> square[0,:] = [-0.5,-0.5]
238    >>> square[1,:] = [0.5,-0.5]
239    >>> square[2,:] = [0.5,0.5]
240    >>> square[3,:] = [-0.5,0.5]
241    >>> max_coords_poly(square)
242    [-0.5, 0.5], [-0.5, 0.5], [0.5, 0.5], 0.5
243    """
244    fname = 'max_coords_poly'
245
246    # x-coordinate min/max
247    nx = np.min(polygon[:,1])
248    xx = np.max(polygon[:,1])
249
250    # y-coordinate min/max
251    ny = np.min(polygon[:,0])
252    xy = np.max(polygon[:,0])
253
254    # x/y-coordinate maximum of absolute values
255    axx = np.max(np.abs(polygon[:,1]))
256    ayx = np.max(np.abs(polygon[:,0]))
257
258    # absolute maximum
259    xyx = np.max([axx, ayx])
260
261    return [nx, xx], [ny, xy], [ayx, axx], xyx
262
263def mirror_polygon(polygon,axis):
264    """ Function to reflex a polygon for a given axis
265      polygon: polygon to mirror
266      axis: axis at which mirror is located ('x' or 'y')
267    """
268    fname = 'mirror_polygon'
269
270    reflex = np.zeros(polygon.shape, dtype=np.float)
271
272    N = polygon.shape[0]
273    if axis == 'x':
274        for iv in range(N):
275            reflex[iv,:] = [-polygon[iv,0], polygon[iv,1]]
276    elif axis == 'y':
277        for iv in range(N):
278            reflex[iv,:] = [polygon[iv,0], -polygon[iv,1]]
279
280    return reflex
281
282####### ###### ##### #### ### ## #
283# Shapes/objects
284
285def surface_sphere(radii,Npts):
286    """ Function to provide an sphere as matrix of x,y,z coordinates
287      radii: radii of the sphere
288      Npts: number of points to discretisize longitues (half for latitudes)
289    """
290    fname = 'surface_sphere'
291
292    sphereup = np.zeros((3,Npts/2,Npts), dtype=np.float)
293    spheredown = np.zeros((3,Npts/2,Npts), dtype=np.float)
294    for ia in range(Npts):
295        alpha = ia*2*np.pi/(Npts-1)
296        for ib in range(Npts/2):
297            beta = ib*np.pi/(2.*(Npts/2-1))
298            sphereup[:,ib,ia] = position_sphere(radii, alpha, beta)
299        for ib in range(Npts/2):
300            beta = -ib*np.pi/(2.*(Npts/2-1))
301            spheredown[:,ib,ia] = position_sphere(radii, alpha, beta)
302
303    return sphereup, spheredown
304
305def ellipse_polar(c, a, b, Nang=100):
306    """ Function to determine an ellipse from its center and polar coordinates
307        FROM: https://en.wikipedia.org/wiki/Ellipse
308      c= coordinates of the center
309      a= distance major axis
310      b= distance minor axis
311      Nang= number of angles to use
312    """
313    fname = 'ellipse_polar'
314
315    if np.mod(Nang,2) == 0: Nang=Nang+1
316 
317    dtheta = 2*np.pi/(Nang-1)
318
319    ellipse = np.zeros((Nang,2), dtype=np.float)
320    for ia in range(Nang):
321        theta = dtheta*ia
322        rad = a*b/np.sqrt( (b*np.cos(theta))**2 + (a*np.sin(theta))**2 )
323        x = rad*np.cos(theta)
324        y = rad*np.sin(theta)
325        ellipse[ia,:] = [y+c[0],x+c[1]]
326
327    return ellipse
328
329def hyperbola_polar(a, b, Nang=100):
330    """ Fcuntion to determine an hyperbola in polar coordinates
331        FROM: https://en.wikipedia.org/wiki/Hyperbola#Polar_coordinates
332          x^2/a^2 - y^2/b^2 = 1
333      a= x-parameter
334      y= y-parameter
335      Nang= number of angles to use
336      DOES NOT WORK!!!!
337    """
338    fname = 'hyperbola_polar'
339
340    dtheta = 2.*np.pi/(Nang-1)
341
342    # Positive branch
343    hyperbola_p = np.zeros((Nang,2), dtype=np.float)
344    for ia in range(Nang):
345        theta = dtheta*ia
346        x = a*np.cosh(theta)
347        y = b*np.sinh(theta)
348        hyperbola_p[ia,:] = [y,x]
349
350    # Negative branch
351    hyperbola_n = np.zeros((Nang,2), dtype=np.float)
352    for ia in range(Nang):
353        theta = dtheta*ia
354        x = -a*np.cosh(theta)
355        y = b*np.sinh(theta)
356        hyperbola_n[ia,:] = [y,x]
357
358    return hyperbola_p, hyperbola_n
359
360def circ_sec(ptA, ptB, radii, Nang=100):
361    """ Function union of point A and B by a section of a circle
362      ptA= coordinates od the point A [yA, xA]
363      ptB= coordinates od the point B [yB, xB]
364      radii= radi of the circle to use to unite the points
365      Nang= amount of angles to use
366    """
367    fname = 'circ_sec'
368
369    distAB = dist_points(ptA,ptB)
370
371    if distAB > radii:
372        print errormsg
373        print '  ' + fname + ': radii=', radii, " too small for the distance " +     \
374          "between points !!"
375        print '    distance between points:', distAB
376        quit(-1)
377
378    # Coordinate increments
379    dAB = np.abs(ptA-ptB)
380
381    # angle of the circular section joining points
382    alpha = 2.*np.arcsin((distAB/2.)/radii)
383
384    # center along coincident bisection of the union
385    xcc = -radii
386    ycc = 0.
387
388    # Getting the arc of the circle at the x-axis
389    dalpha = alpha/(Nang-1)
390    circ_sec = np.zeros((Nang,2), dtype=np.float)
391    for ia in range(Nang):
392        alpha = dalpha*ia
393        x = radii*np.cos(alpha)
394        y = radii*np.sin(alpha)
395
396        circ_sec[ia,:] = [y+ycc,x+xcc]
397   
398    # Angle of the points
399    theta = np.arctan2(ptB[0]-ptA[0],ptB[1]-ptA[1])
400
401    # rotating angle of the circ
402    rotangle = theta + 3.*np.pi/2. - alpha/2.
403
404    #print 'alpha:', alpha*180./np.pi, 'theta:', theta*180./np.pi, 'rotangle:', rotangle*180./np.pi
405 
406
407    # rotating the arc along the x-axis
408    rotcirc_sec = rotate_polygon_2D(circ_sec, rotangle)
409
410    # Moving arc to the ptA
411    circ_sec = rotcirc_sec + ptA
412
413    return circ_sec
414
415def p_square(face, N=5):
416    """ Function to get a polygon square
417      face: length of the face of the square
418      N: number of points of the polygon
419    """
420    fname = 'p_square'
421
422    square = np.zeros((N,2), dtype=np.float)
423
424    f2 = face/2.
425    N4 = N/4
426    df = face/(N4)
427    # SW-NW
428    for ip in range(N4):
429        square[ip,:] = [-f2+ip*df,-f2]
430    # NW-NE
431    for ip in range(N4):
432        square[ip+N4,:] = [f2,-f2+ip*df]
433    # NE-SE
434    for ip in range(N4):
435        square[ip+2*N4,:] = [f2-ip*df,f2]
436    N42 = N-3*N4-1
437    df = face/(N42)
438    # SE-SW
439    for ip in range(N42):
440        square[ip+3*N4,:] = [-f2,f2-ip*df]
441    square[N-1,:] = [-f2,-f2]
442
443    return square
444
445def p_circle(radii, N=50):
446    """ Function to get a polygon of a circle
447      radii: length of the radii of the circle
448      N: number of points of the polygon
449    """
450    fname = 'p_circle'
451
452    circle = np.zeros((N,2), dtype=np.float)
453
454    dangle = 2.*np.pi/(N-1)
455
456    for ia in range(N):
457        circle[ia,:] = [radii*np.sin(ia*dangle), radii*np.cos(ia*dangle)]
458
459    circle[N-1,:] = [0., radii]
460
461    return circle
462
463def p_triangle(p1, p2, p3, N=4):
464    """ Function to provide the polygon of a triangle from its 3 vertices
465      p1: vertex 1 [y,x]
466      p2: vertex 2 [y,x]
467      p3: vertex 3 [y,x]
468      N: number of vertices of the triangle
469    """
470    fname = 'p_triangle'
471
472    triangle = np.zeros((N,2), dtype=np.float)
473
474    N3 = N / 3
475    # 1-2
476    dx = (p2[1]-p1[1])/N3
477    dy = (p2[0]-p1[0])/N3
478    for ip in range(N3):
479        triangle[ip,:] = [p1[0]+ip*dy,p1[1]+ip*dx]
480    # 2-3
481    dx = (p3[1]-p2[1])/N3
482    dy = (p3[0]-p2[0])/N3
483    for ip in range(N3):
484        triangle[ip+N3,:] = [p2[0]+ip*dy,p2[1]+ip*dx]
485    # 3-1
486    N32 = N - 2*N/3
487    dx = (p1[1]-p3[1])/N32
488    dy = (p1[0]-p3[0])/N32
489    for ip in range(N32):
490        triangle[ip+2*N3,:] = [p3[0]+ip*dy,p3[1]+ip*dx]
491
492    triangle[N-1,:] = p1
493
494    return triangle
495
496def p_spiral(loops, eradii, N=1000):
497    """ Function to provide a polygon of an Archimedean spiral
498        FROM: https://en.wikipedia.org/wiki/Spiral
499      loops: number of loops of the spiral
500      eradii: length of the radii of the final spiral
501      N: number of points of the polygon
502    """
503    fname = 'p_spiral'
504
505    spiral = np.zeros((N,2), dtype=np.float)
506
507    dangle = 2.*np.pi*loops/(N-1)
508    dr = eradii*1./(N-1)
509
510    for ia in range(N):
511        radii = dr*ia
512        spiral[ia,:] = [radii*np.sin(ia*dangle), radii*np.cos(ia*dangle)]
513
514    return spiral
515
516def p_reg_polygon(Nv, lf, N=50):
517    """ Function to provide a regular polygon of Nv vertices
518      Nv: number of vertices
519      lf: length of the face
520      N: number of points
521    """
522    fname = 'p_reg_polygon'
523
524    reg_polygon = np.zeros((N,2), dtype=np.float)
525
526    # Number of points per vertex
527    Np = N/Nv
528    # Angle incremental between vertices
529    da = 2.*np.pi/Nv
530    # Radii of the circle according to lf
531    radii = lf*Nv/(2*np.pi)
532
533    iip = 0
534    for iv in range(Nv-1):
535        # Characteristics between vertices iv and iv+1
536        av1 = da*iv
537        v1 = [radii*np.sin(av1), radii*np.cos(av1)]
538        av2 = da*(iv+1)
539        v2 = [radii*np.sin(av2), radii*np.cos(av2)]
540        dx = (v2[1]-v1[1])/Np
541        dy = (v2[0]-v1[0])/Np
542        for ip in range(Np):
543            reg_polygon[ip+iv*Np,:] = [v1[0]+dy*ip,v1[1]+dx*ip]
544
545    # Characteristics between vertices Nv and 1
546
547    # Number of points per vertex
548    Np2 = N - Np*(Nv-1)
549
550    av1 = da*Nv
551    v1 = [radii*np.sin(av1), radii*np.cos(av1)]
552    av2 = 0.
553    v2 = [radii*np.sin(av2), radii*np.cos(av2)]
554    dx = (v2[1]-v1[1])/Np2
555    dy = (v2[0]-v1[0])/Np2
556    for ip in range(Np2):
557        reg_polygon[ip+(Nv-1)*Np,:] = [v1[0]+dy*ip,v1[1]+dx*ip]
558
559    return reg_polygon
560
561def p_reg_star(Nv, lf, freq, vs=0, N=50):
562    """ Function to provide a regular star of Nv vertices
563      Nv: number of vertices
564      lf: length of the face of the regular polygon
565      freq: frequency of union of vertices ('0', for just centered to zero arms)
566      vs: vertex from which start (0 being first [0,lf])
567      N: number of points
568    """
569    fname = 'p_reg_star'
570
571    reg_star = np.zeros((N,2), dtype=np.float)
572
573    # Number of arms of the star
574    if freq != 0 and np.mod(Nv,freq) == 0: 
575        Na = Nv/freq + 1
576    else:
577        Na = Nv
578
579    # Number of points per arm
580    Np = N/Na
581    # Angle incremental between vertices
582    da = 2.*np.pi/Nv
583    # Radii of the circle according to lf
584    radii = lf*Nv/(2*np.pi)
585
586    iip = 0
587    av1 = vs*da
588    for iv in range(Na-1):
589        # Characteristics between vertices iv and iv+1
590        v1 = [radii*np.sin(av1), radii*np.cos(av1)]
591        if freq != 0:
592            av2 = av1 + da*freq
593            v2 = [radii*np.sin(av2), radii*np.cos(av2)]
594        else:
595            v2 = [0., 0.]
596            av2 = av1 + da
597        dx = (v2[1]-v1[1])/(Np-1)
598        dy = (v2[0]-v1[0])/(Np-1)
599        for ip in range(Np):
600            reg_star[ip+iv*Np,:] = [v1[0]+dy*ip,v1[1]+dx*ip]
601        if av2 > 2.*np.pi: av1 = av2 - 2.*np.pi
602        else: av1 = av2 + 0.
603
604    iv = Na-1
605    # Characteristics between vertices Na and 1
606    Np2 = N-Np*iv
607    v1 = [radii*np.sin(av1), radii*np.cos(av1)]
608    if freq != 0:
609        av2 = vs*da
610        v2 = [radii*np.sin(av2), radii*np.cos(av2)]
611    else:
612        v2 = [0., 0.]
613    dx = (v2[1]-v1[1])/(Np2-1)
614    dy = (v2[0]-v1[0])/(Np2-1)
615    for ip in range(Np2):
616        reg_star[ip+iv*Np,:] = [v1[0]+dy*ip,v1[1]+dx*ip]
617
618    return reg_star
619
620# Combined objects
621##
622
623# FROM: http://www.photographers1.com/Sailing/NauticalTerms&Nomenclature.html
624def zsailing_boat(length=10., beam=1., lbeam=0.4, sternbp=0.5):
625    """ Function to define an schematic boat from the z-plane
626      length: length of the boat (without stern, default 10)
627      beam: beam of the boat (default 1)
628      lbeam: length at beam (as percentage of length, default 0.4)
629      sternbp: beam at stern (as percentage of beam, default 0.5)
630    """
631    fname = 'zsailing_boat'
632
633    bow = np.array([length, 0.])
634    maxportside = np.array([length*lbeam, -beam])
635    maxstarboardside = np.array([length*lbeam, beam])
636    portside = np.array([0., -beam*sternbp])
637    starboardside = np.array([0., beam*sternbp])
638
639    # forward section
640    fportsaid = circ_sec(bow,maxportside, length*2)
641    fstarboardsaid = circ_sec(maxstarboardside, bow, length*2)
642    # aft section
643    aportsaid = circ_sec(maxportside, portside, length*2)
644    astarboardsaid = circ_sec(starboardside, maxstarboardside, length*2)
645    # stern
646    stern = circ_sec(portside, starboardside, length*2)
647
648    dpts = stern.shape[0]
649    boat = np.zeros((dpts*5,2), dtype=np.float)
650
651    boat[0:dpts,:] = fportsaid
652    boat[dpts:2*dpts,:] = aportsaid
653    boat[2*dpts:3*dpts,:] = stern
654    boat[3*dpts:4*dpts,:] = astarboardsaid
655    boat[4*dpts:5*dpts,:] = fstarboardsaid
656
657    fname = 'boat_L' + str(int(length*100.)) + '_B' + str(int(beam*100.)) + '_lb' +  \
658      str(int(lbeam*100.)) + '_sb' + str(int(sternbp*100.)) + '.dat'
659    if not os.path.isfile(fname):
660        print infmsg
661        print '  ' + fname + ": writting boat coordinates file '" + fname + "' !!"
662        of = open(fname, 'w')
663        of.write('# boat file with Length: ' + str(length) +' max_beam: '+str(beam)+ \
664          'length_at_max_beam:' + str(lbeam) + '% beam at stern: ' + str(sternbp)+   \
665          ' %\n')
666        for ip in range(dpts*5):
667            of.write(str(boat[ip,0]) + ' ' + str(boat[ip,1]) + '\n')
668       
669        of.close()
670        print fname + ": Successfull written '" + fname + "' !!"
671 
672    return boat
673
674def write_join_poly(polys, flname='join_polygons.dat'):
675    """ Function to write an ASCII file with the combination of polygons
676      polys: dictionary with the names of the different polygons
677      flname: name of the ASCII file
678    """
679    fname = 'write_join_poly'
680
681    of = open(flname, 'w')
682
683    for polyn in polys.keys():
684        vertices = polys[polyn]
685        Npts = vertices.shape[0]
686        for ip in range(Npts):
687            of.write(polyn+' '+str(vertices[ip,1]) + ' ' + str(vertices[ip,0]) + '\n')
688
689    of.close()
690
691    return
692
693def read_join_poly(flname='join_polygons.dat'):
694    """ Function to read an ASCII file with the combination of polygons
695      flname: name of the ASCII file
696    """
697    fname = 'read_join_poly'
698
699    of = open(flname, 'r')
700
701    polys = {}
702    polyn = ''
703    poly = []
704    for line in of:
705        if len(line) > 1: 
706            linevals = line.replace('\n','').split(' ')
707            if polyn != linevals[0]:
708                if len(poly) > 1:
709                    polys[polyn] = np.array(poly)
710                polyn = linevals[0]
711                poly = []
712                poly.append([np.float(linevals[2]), np.float(linevals[1])])
713            else:
714                poly.append([np.float(linevals[2]), np.float(linevals[1])])
715
716    of.close()
717    polys[polyn] = np.array(poly)
718
719    return polys
720
721####### ####### ##### #### ### ## #
722# Plotting
723
724def plot_sphere(iazm=-60., iele=30., dist=10., Npts=100, radii=10,                   \
725  drwsfc=[True,True], colsfc=['#AAAAAA','#646464'],                                  \
726  drwxline = True, linex=[':','b',2.], drwyline = True, liney=[':','r',2.],          \
727  drwzline = True, linez=['-.','g',2.], drwxcline=[True,True],                       \
728  linexc=[['-','#646400',1.],['--','#646400',1.]],                                   \
729  drwequator=[True,True], lineeq=[['-','#AA00AA',1.],['--','#AA00AA',1.]],           \
730  drwgreeenwhich=[True,True], linegw=[['-','k',1.],['--','k',1.]]):
731    """ Function to plot an sphere and determine which standard lines will be also
732        drawn
733      iazm: azimut of the camera form the sphere
734      iele: elevation of the camera form the sphere
735      dist: distance of the camera form the sphere
736      Npts: Resolution for the sphere
737      radii: radius of the sphere
738      drwsfc: whether 'up' and 'down' portions of the sphere should be drawn
739      colsfc: colors of the surface of the sphere portions ['up', 'down']
740      drwxline: whether x-axis line should be drawn
741      linex: properties of the x-axis line ['type', 'color', 'wdith']
742      drwyline: whether y-axis line should be drawn
743      liney: properties of the y-axis line ['type', 'color', 'wdith']
744      drwzline: whether z-axis line should be drawn
745      linez: properties of the z-axis line ['type', 'color', 'wdith']
746      drwequator: whether 'front' and 'back' portions of the Equator should be drawn
747      lineeq: properties of the lines 'front' and 'back' of the Equator
748      drwgreeenwhich: whether 'front', 'back' portions of Greenqhich should be drawn
749      linegw: properties of the lines 'front' and 'back' Greenwhich
750      drwxcline: whether 'front', 'back' 90 line (lon=90., lon=270.) should be drawn
751      linexc: properties of the lines 'front' and 'back' for the 90 line
752    """
753    fname = 'plot_sphere'
754
755    iazmrad = iazm*np.pi/180.
756    ielerad = iele*np.pi/180.
757
758    # 3D surface Sphere
759    sfcsphereu, sfcsphered = surface_sphere(radii,Npts)
760   
761    # greenwhich
762    if iazmrad > np.pi/2. and iazmrad < 3.*np.pi/2.:
763        ia=np.pi-ielerad
764    else:
765        ia=0.-ielerad
766    ea=ia+np.pi
767    da = (ea-ia)/(Npts-1)
768    beta = np.arange(ia,ea+da,da)[0:Npts]
769    alpha = np.zeros((Npts), dtype=np.float)
770    greenwhichc = spheric_line(radii,alpha,beta)
771    ia=ea+0.
772    ea=ia+np.pi
773    da = (ea-ia)/(Npts-1)
774    beta = np.arange(ia,ea+da,da)[0:Npts]
775    greenwhichd = spheric_line(radii,alpha,beta)
776
777    # Equator
778    ia=np.pi-iazmrad/2.
779    ea=ia+np.pi
780    da = (ea-ia)/(Npts-1)
781    alpha = np.arange(ia,ea+da,da)[0:Npts]
782    beta = np.zeros((Npts), dtype=np.float)
783    equatorc = spheric_line(radii,alpha,beta)
784    ia=ea+0.
785    ea=ia+np.pi
786    da = (ea-ia)/(Npts-1)
787    alpha = np.arange(ia,ea+da,da)[0:Npts]
788    equatord = spheric_line(radii,alpha,beta)
789
790    # 90 line
791    if iazmrad > np.pi and iazmrad < 2.*np.pi:
792        ia=3.*np.pi/2. + ielerad
793    else:
794        ia=np.pi/2. - ielerad
795    if ielerad < 0.:
796        ia = ia + np.pi
797    ea=ia+np.pi
798    da = (ea-ia)/(Npts-1)
799    beta = np.arange(ia,ea+da,da)[0:Npts]
800    alpha = np.ones((Npts), dtype=np.float)*np.pi/2.
801    xclinec = spheric_line(radii,alpha,beta)
802    ia=ea+0.
803    ea=ia+np.pi
804    da = (ea-ia)/(Npts-1)
805    beta = np.arange(ia,ea+da,da)[0:Npts]
806    xclined = spheric_line(radii,alpha,beta)
807
808    # x line
809    xline = np.zeros((2,3), dtype=np.float)
810    xline[0,:] = position_sphere(radii, 0., 0.)
811    xline[1,:] = position_sphere(radii, np.pi, 0.)
812
813    # y line
814    yline = np.zeros((2,3), dtype=np.float)
815    yline[0,:] = position_sphere(radii, np.pi/2., 0.)
816    yline[1,:] = position_sphere(radii, 3*np.pi/2., 0.)
817
818    # z line
819    zline = np.zeros((2,3), dtype=np.float)
820    zline[0,:] = position_sphere(radii, 0., np.pi/2.)
821    zline[1,:] = position_sphere(radii, 0., -np.pi/2.)
822
823    fig = plt.figure()
824    ax = fig.gca(projection='3d')
825
826    # Sphere surface
827    if drwsfc[0]:
828        ax.plot_surface(sfcsphereu[0,:,:], sfcsphereu[1,:,:], sfcsphereu[2,:,:],     \
829          color=colsfc[0])
830    if drwsfc[1]:
831        ax.plot_surface(sfcsphered[0,:,:], sfcsphered[1,:,:], sfcsphered[2,:,:],     \
832          color=colsfc[1])
833
834    # greenwhich
835    linev = linegw[0]
836    if drwgreeenwhich[0]:
837        ax.plot(greenwhichc[:,0], greenwhichc[:,1], greenwhichc[:,2], linev[0],      \
838          color=linev[1], linewidth=linev[2],  label='Greenwich')
839    linev = linegw[1]
840    if drwgreeenwhich[1]:
841        ax.plot(greenwhichd[:,0], greenwhichd[:,1], greenwhichd[:,2], linev[0],      \
842          color=linev[1], linewidth=linev[2])
843
844    # Equator
845    linev = lineeq[0]
846    if drwequator[0]:
847        ax.plot(equatorc[:,0], equatorc[:,1], equatorc[:,2], linev[0],               \
848          color=linev[1], linewidth=linev[2], label='Equator')
849    linev = lineeq[1]
850    if drwequator[1]:
851        ax.plot(equatord[:,0], equatord[:,1], equatord[:,2], linev[0],               \
852          color=linev[1], linewidth=linev[2])
853
854    # 90line
855    linev = linexc[0]
856    if drwxcline[0]:
857        ax.plot(xclinec[:,0], xclinec[:,1], xclinec[:,2], linev[0], color=linev[1],  \
858          linewidth=linev[2], label='90-line')
859    linev = linexc[1]
860    if drwxcline[1]:
861        ax.plot(xclined[:,0], xclined[:,1], xclined[:,2], linev[0], color=linev[1],  \
862          linewidth=linev[2])
863
864    # x line
865    linev = linex
866    if drwxline:
867        ax.plot([xline[0,0],xline[1,0]], [xline[0,1],xline[1,1]],                    \
868          [xline[0,2],xline[1,2]], linev[0], color=linev[1], linewidth=linev[2],  label='xline')
869
870    # y line
871    linev = liney
872    if drwyline:
873        ax.plot([yline[0,0],yline[1,0]], [yline[0,1],yline[1,1]],                    \
874          [yline[0,2],yline[1,2]], linev[0], color=linev[1], linewidth=linev[2],  label='yline')
875
876    # z line
877    linev = linez
878    if drwzline:
879        ax.plot([zline[0,0],zline[1,0]], [zline[0,1],zline[1,1]],                    \
880          [zline[0,2],zline[1,2]], linev[0], color=linev[1], linewidth=linev[2],  label='zline')
881
882    plt.legend()
883
884    return fig, ax
Note: See TracBrowser for help on using the repository browser.