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

Last change on this file since 2609 was 2609, checked in by lfita, 5 years ago

Adding:

  • `add_secpolygon_list': Function to add a range of points of a polygon into a list (previously add, but uncommented)
  • `rm_consecpt_polygon': Function to remove consecutive same point of a polygon
File size: 124.0 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
17import generic_tools as gen
18import numpy.ma as ma
19import module_ForSci as sci
20
21errormsg = 'ERROR -- error -- ERROR -- error'
22infmsg = 'INFORMATION -- information -- INFORMATION -- information'
23
24####### Contents:
25# add_secpolygon_list: Function to add a range of points of a polygon into a list
26# cut_between_[x/y]polygon: Function to cut a polygon between 2 given value of the [x/y]-axis
27# cut_[x/y]polygon: Function to cut a polygon from a given value of the [x/y]-axis
28# deg_deci: Function to pass from degrees [deg, minute, sec] to decimal angles [rad]
29# dist_points: Function to provide the distance between two points
30# join_circ_sec: Function to join aa series of points by circular segments
31# join_circ_sec_rand: Function to join aa series of points by circular segments with
32#   random perturbations
33# max_coords_poly: Function to provide the extremes of the coordinates of a polygon
34# mirror_polygon: Function to reflex a polygon for a given axis
35# position_sphere: Function to tranform fom a point in lon, lat deg coordinates to
36#   cartesian coordinates over an sphere
37# read_join_poly: Function to read an ASCII file with the combination of polygons
38# rm_consecpt_polygon: Function to remove consecutive same point of a polygon
39# rotate_2D: Function to rotate a vector by a certain angle in the plain
40# rotate_polygon_2D: Function to rotate 2D plain the vertices of a polygon
41# rotate_line2D: Function to rotate a line given by 2 pairs of x,y coordinates by a
42#   certain angle in the plain
43# rotate_lines2D: Function to rotate multiple lines given by mulitple pars of x,y
44#   coordinates by a certain angle in the plain
45# spheric_line: Function to transform a series of locations in lon, lat coordinates
46#   to x,y,z over an 3D spaceFunction to provide coordinates of a line  on a 3D space
47# val_consec_between: Function to provide if a given value is between two consecutive ones
48# write_join_poly: Function to write an ASCII file with the combination of polygons
49
50## Shapes/objects
51# buoy1: Function to draw a buoy as superposition of prism and section of ball
52# band_lighthouse: Function to plot a lighthouse with spiral bands
53# circ_sec: Function union of point A and B by a section of a circle
54# ellipse_polar: Function to determine an ellipse from its center and polar coordinates
55# green_buoy1: Function to draw a green mark buoy using buoy1
56# isolateddanger_buoy1: Function to draw an isolated danger buoy using buoy1
57# p_angle_triangle: Function to draw a triangle by an initial point and two
58#   consecutive angles and the first length of face. The third angle and 2 and 3rd
59#   face will be computed accordingly the provided values
60# p_doubleArrow: Function to provide an arrow with double lines
61# p_circle: Function to get a polygon of a circle
62# p_cross_width: Function to draw a cross with arms with a given width and an angle
63# p_prism: Function to get a polygon prism
64# p_reg_polygon: Function to provide a regular polygon of Nv vertices
65# p_reg_star: Function to provide a regular star of Nv vertices
66# p_sinusiode: Function to get coordinates of a sinusoidal curve
67# p_square: Function to get a polygon square
68# p_spiral: Function to provide a polygon of an Archimedean spiral
69# p_triangle: Function to provide the polygon of a triangle from its 3 vertices
70# prefchannelport[A/B]_buoy1: Function to draw a preferred channel port system
71#   [A/B] buoy using buoy1
72# prefchannelstarboard[A/B]_buoy1: Function to draw a preferred channel starboard
73#   system [A/B] buoy using buoy1
74# red_buoy1: Function to draw a red mark buoy using buoy1
75# safewater_buoy1: Function to draw a safe water mark buoy using buoy1
76# special_buoy1: Function to draw an special mark buoy using buoy1
77# surface_sphere: Function to provide an sphere as matrix of x,y,z coordinates
78# z_boat: Function to define an schematic boat from the z-plane
79# zsailing_boat: Function to define an schematic sailing boat from the z-plane with sails
80# zisland1: Function to draw an island from z-axis as the union of a series of points by
81#   circular segments
82
83## Plotting
84# paint_filled: Function to draw an object filling given sections
85# plot_sphere: Function to plot an sphere and determine which standard lines will be
86#   also drawn
87# [north/east/south/west_buoy1: Function to draw a [North/East/South/West] danger buoy using buoy1
88
89def deg_deci(angle):
90    """ Function to pass from degrees [deg, minute, sec] to decimal angles [rad]
91      angle: list of [deg, minute, sec] to pass
92    >>> deg_deci([41., 58., 34.])
93    0.732621346072
94    """
95    fname = 'deg_deci'
96
97    deg = np.abs(angle[0]) + np.abs(angle[1])/60. + np.abs(angle[2])/3600.
98
99    if angle[0] < 0.: deg = -deg*np.pi/180.
100    else: deg = deg*np.pi/180.
101
102    return deg
103
104def position_sphere(radii, alpha, beta):
105    """ Function to tranform fom a point in lon, lat deg coordinates to cartesian 
106          coordinates over an sphere
107      radii: radii of the sphere
108      alpha: longitude of the point
109      beta: latitude of the point
110    >>> position_sphere(10., 30., 45.)
111    (0.81031678432964027, -5.1903473778327376, 8.5090352453411846
112    """
113    fname = 'position_sphere'
114
115    xpt = radii*np.cos(beta)*np.cos(alpha)
116    ypt = radii*np.cos(beta)*np.sin(alpha)
117    zpt = radii*np.sin(beta)
118
119    return xpt, ypt, zpt
120
121def spheric_line(radii,lon,lat):
122    """ Function to transform a series of locations in lon, lat coordinates to x,y,z
123          over an 3D space
124      radii: radius of the sphere
125      lon: array of angles along longitudes
126      lat: array of angles along latitudes
127    """
128    fname = 'spheric_line'
129
130    Lint = lon.shape[0]
131    coords = np.zeros((Lint,3), dtype=np.float)
132
133    for iv in range(Lint):
134        coords[iv,:] = position_sphere(radii, lon[iv], lat[iv])
135
136    return coords
137
138def rotate_2D(vector, angle):
139    """ Function to rotate a vector by a certain angle in the plain
140      vector= vector to rotate [y, x]
141      angle= angle to rotate [rad]
142    >>> rotate_2D(np.array([1.,0.]), np.pi/4.)
143    [ 0.70710678 -0.70710678]
144    """
145    fname = 'rotate_2D'
146
147    rotmat = np.zeros((2,2), dtype=np.float)
148
149    rotmat[0,0] = np.cos(angle)
150    rotmat[0,1] = -np.sin(angle)
151    rotmat[1,0] = np.sin(angle)
152    rotmat[1,1] = np.cos(angle)
153
154    rotvector = np.zeros((2), dtype=np.float)
155
156    vecv = np.zeros((2), dtype=np.float)
157
158    # Unifying vector
159    modvec = vector[0]**2+vector[1]**2
160    if modvec != 0: 
161        vecv[0] = vector[1]/modvec
162        vecv[1] = vector[0]/modvec
163
164        rotvec = np.matmul(rotmat, vecv)
165        rotvec = np.where(np.abs(rotvec) < 1.e-7, 0., rotvec)
166
167        rotvector[0] = rotvec[1]*modvec
168        rotvector[1] = rotvec[0]*modvec
169
170    return rotvector
171
172def rotate_polygon_2D(vectors, angle):
173    """ Function to rotate 2D plain the vertices of a polygon
174      line= matrix of vectors to rotate
175      angle= angle to rotate [rad]
176    >>> square = np.zeros((4,2), dtype=np.float)
177    >>> square[0,:] = [-0.5,-0.5]
178    >>> square[1,:] = [0.5,-0.5]
179    >>> square[2,:] = [0.5,0.5]
180    >>> square[3,:] = [-0.5,0.5]
181    >>> rotate_polygon_2D(square, np.pi/4.)
182    [[-0.70710678  0.        ]
183     [ 0.         -0.70710678]
184     [ 0.70710678  0.        ]
185     [ 0.          0.70710678]]
186    """
187    fname = 'rotate_polygon_2D'
188
189    rotvecs = np.zeros(vectors.shape, dtype=np.float)
190
191    Nvecs = vectors.shape[0]
192    for iv in range(Nvecs):
193        rotvecs[iv,:] = rotate_2D(vectors[iv,:], angle)
194
195    return rotvecs
196
197def rotate_line2D(line, angle):
198    """ Function to rotate a line given by 2 pairs of x,y coordinates by a certain
199          angle in the plain
200      line= line to rotate as couple of points [[y0,x0], [y1,x1]]
201      angle= angle to rotate [rad]
202    >>> rotate_line2D(np.array([[0.,0.], [1.,0.]]), np.pi/4.)
203    [[ 0.          0.        ]
204     [0.70710678  -0.70710678]]
205    """
206    fname = 'rotate_2D'
207
208    rotline = np.zeros((2,2), dtype=np.float)
209    rotline[0,:] = rotate_2D(line[0,:], angle)
210    rotline[1,:] = rotate_2D(line[1,:], angle)
211
212    return rotline
213
214def rotate_lines2D(lines, angle):
215    """ Function to rotate multiple lines given by mulitple pars of x,y coordinates 
216          by a certain angle in the plain
217      line= matrix of N couples of points [N, [y0,x0], [y1,x1]]
218      angle= angle to rotate [rad]
219    >>> square = np.zeros((4,2,2), dtype=np.float)
220    >>> square[0,0,:] = [-0.5,-0.5]
221    >>> square[0,1,:] = [0.5,-0.5]
222    >>> square[1,0,:] = [0.5,-0.5]
223    >>> square[1,1,:] = [0.5,0.5]
224    >>> square[2,0,:] = [0.5,0.5]
225    >>> square[2,1,:] = [-0.5,0.5]
226    >>> square[3,0,:] = [-0.5,0.5]
227    >>> square[3,1,:] = [-0.5,-0.5]
228    >>> rotate_lines2D(square, np.pi/4.)
229    [[[-0.70710678  0.        ]
230      [ 0.         -0.70710678]]
231
232     [[ 0.         -0.70710678]
233      [ 0.70710678  0.        ]]
234
235     [[ 0.70710678  0.        ]
236      [ 0.          0.70710678]]
237
238     [[ 0.          0.70710678]
239      [-0.70710678  0.        ]]]
240    """
241    fname = 'rotate_lines2D'
242
243    rotlines = np.zeros(lines.shape, dtype=np.float)
244
245    Nlines = lines.shape[0]
246    for il in range(Nlines):
247        line = np.zeros((2,2), dtype=np.float)
248        line[0,:] = lines[il,0,:]
249        line[1,:] = lines[il,1,:]
250
251        rotlines[il,:,:] = rotate_line2D(line, angle)
252
253    return rotlines
254
255def dist_points(ptA, ptB):
256    """ Function to provide the distance between two points
257      ptA: coordinates of the point A [yA, xA]
258      ptB: coordinates of the point B [yB, xB]
259    >>> dist_points([1.,1.], [-1.,-1.])
260    2.82842712475
261    """
262    fname = 'dist_points'
263
264    dist = np.sqrt( (ptA[0]-ptB[0])**2 + (ptA[1]-ptB[1])**2)
265
266    return dist
267
268def max_coords_poly(polygon):
269    """ Function to provide the extremes of the coordinates of a polygon
270      polygon: coordinates [Nvertexs, 2] of a polygon
271    >>> square = np.zeros((4,2), dtype=np.float)
272    >>> square[0,:] = [-0.5,-0.5]
273    >>> square[1,:] = [0.5,-0.5]
274    >>> square[2,:] = [0.5,0.5]
275    >>> square[3,:] = [-0.5,0.5]
276    >>> max_coords_poly(square)
277    [-0.5, 0.5], [-0.5, 0.5], [0.5, 0.5], 0.5
278    """
279    fname = 'max_coords_poly'
280
281    # x-coordinate min/max
282    nx = np.min(polygon[:,1])
283    xx = np.max(polygon[:,1])
284
285    # y-coordinate min/max
286    ny = np.min(polygon[:,0])
287    xy = np.max(polygon[:,0])
288
289    # x/y-coordinate maximum of absolute values
290    axx = np.max(np.abs(polygon[:,1]))
291    ayx = np.max(np.abs(polygon[:,0]))
292
293    # absolute maximum
294    xyx = np.max([axx, ayx])
295
296    return [nx, xx], [ny, xy], [ayx, axx], xyx
297
298def mirror_polygon(polygon,axis):
299    """ Function to reflex a polygon for a given axis
300      polygon: polygon to mirror
301      axis: axis at which mirror is located ('x' or 'y')
302    """
303    fname = 'mirror_polygon'
304
305    reflex = np.zeros(polygon.shape, dtype=np.float)
306
307    N = polygon.shape[0]
308    if axis == 'x':
309        for iv in range(N):
310            reflex[iv,:] = [-polygon[iv,0], polygon[iv,1]]
311    elif axis == 'y':
312        for iv in range(N):
313            reflex[iv,:] = [polygon[iv,0], -polygon[iv,1]]
314
315    return reflex
316
317def join_circ_sec(points, radfrac=3., N=200):
318    """ Function to join aa series of points by circular segments
319      points: main points of the island (clockwise ordered, to be joined by circular
320        segments of radii as the radfrac factor of the distance between
321        consecutive points)
322      radfrac: multiplicative factor of the distance between consecutive points to
323        draw the circular segment (3., default)
324      N: number of points (200, default)
325    """
326    fname = 'join_circ_sec'
327
328    jcirc_sec = np.ones((N,2), dtype=np.float)
329
330    # main points
331    lpoints = list(points)
332    Npts = len(lpoints)
333    Np = int(N/(Npts+1))
334    for ip in range(Npts-1):
335        p1 = lpoints[ip]
336        p2 = lpoints[ip+1]
337        dps = dist_points(p1, p2)
338        jcirc_sec[Np*ip:Np*(ip+1),:] = circ_sec(p1, p2, dps*radfrac, 'short', Np)
339
340    Np2 = N - (Npts-1)*Np
341    p1 = lpoints[Npts-1]
342    p2 = lpoints[0]
343    dps = dist_points(p1, p2)
344    jcirc_sec[(Npts-1)*Np:N,:] = circ_sec(p1, p2, dps*3., 'short', Np2)
345
346    return jcirc_sec
347
348def join_circ_sec_rand(points, radfrac=3., Lrand=0.1, arc='short', pos='left', N=200):
349    """ Function to join aa series of points by circular segments with random
350        perturbations
351      points: main points of the island (clockwise ordered, to be joined by circular
352        segments of radii as the radfrac factor of the distance between
353        consecutive points)
354      radfrac: multiplicative factor of the distance between consecutive points to
355        draw the circular segment (3., default)
356      Lrand: maximum length of the random perturbation to be added perpendicularly to
357        the direction of the union line between points (0.1, default)
358      arc: type of arc ('short', default)
359      pos: position of arc ('left', default)
360      N: number of points (200, default)
361    """
362    import random
363    fname = 'join_circ_sec_rand'
364
365    jcirc_sec = np.ones((N,2), dtype=np.float)
366
367    # main points
368    lpoints = list(points)
369    Npts = len(lpoints)
370    Np = int(N/(Npts+1))
371    for ip in range(Npts-1):
372        p1 = lpoints[ip]
373        p2 = lpoints[ip+1]
374        dps = dist_points(p1, p2)
375        angle = np.arctan2(p2[0]-p1[0], p2[1]-p1[1]) + np.pi/2.
376        jcirc_sec[Np*ip:Np*(ip+1),:] = circ_sec(p1, p2, dps*radfrac, arc, pos, Np)
377        drand = Lrand*np.array([np.sin(angle), np.cos(angle)])
378        for iip in range(Np*ip,Np*(ip+1)):
379            jcirc_sec[iip,:] = jcirc_sec[iip,:] + drand*random.uniform(-1.,1.)
380
381    Np2 = N - (Npts-1)*Np
382    p1 = lpoints[Npts-1]
383    p2 = lpoints[0]
384    dps = dist_points(p1, p2)
385    angle = np.arctan2(p2[0]-p1[0], p2[1]-p1[1]) + np.pi/2.
386    jcirc_sec[(Npts-1)*Np:N,:] = circ_sec(p1, p2, dps*3., arc, pos, Np2)
387    drand = Lrand*np.array([np.sin(angle), np.cos(angle)])
388    for iip in range(Np*(Npts-1),N):
389        jcirc_sec[iip,:] = jcirc_sec[iip,:] + drand*random.uniform(-1.,1.)
390
391    return jcirc_sec
392
393def write_join_poly(polys, flname='join_polygons.dat'):
394    """ Function to write an ASCII file with the combination of polygons
395      polys: dictionary with the names of the different polygons
396      flname: name of the ASCII file
397    """
398    fname = 'write_join_poly'
399
400    of = open(flname, 'w')
401
402    for polyn in polys.keys():
403        vertices = polys[polyn]
404        Npts = vertices.shape[0]
405        for ip in range(Npts):
406            of.write(polyn+' '+str(vertices[ip,1]) + ' ' + str(vertices[ip,0]) + '\n')
407
408    of.close()
409
410    return
411
412def read_join_poly(flname='join_polygons.dat'):
413    """ Function to read an ASCII file with the combination of polygons
414      flname: name of the ASCII file
415    """
416    fname = 'read_join_poly'
417
418    of = open(flname, 'r')
419
420    polys = {}
421    polyn = ''
422    poly = []
423    for line in of:
424        if len(line) > 1: 
425            linevals = line.replace('\n','').split(' ')
426            if polyn != linevals[0]:
427                if len(poly) > 1:
428                    polys[polyn] = np.array(poly)
429                polyn = linevals[0]
430                poly = []
431                poly.append([np.float(linevals[2]), np.float(linevals[1])])
432            else:
433                poly.append([np.float(linevals[2]), np.float(linevals[1])])
434
435    of.close()
436    polys[polyn] = np.array(poly)
437
438    return polys
439
440def val_consec_between(valA, valB, val):
441    """ Function to provide if a given value is between two consecutive ones
442      valA: first value
443      valB: second value
444      val: value to determine if it is between
445      >>> val_consec_between(0.5,1.5,0.8)
446      True
447      >>> val_consec_between(0.5,1.5.,-0.8)
448      False
449      >>> val_consec_between(0.5,1.5,0.5)
450      True
451      >>> val_consec_between(-1.58, -1.4, -1.5)
452      True
453      >>> val_consec_between(-1.48747753212, -1.57383530044, -1.5)
454      False
455    """
456    fname = 'val_consec_between'
457
458    btw = False
459    diffA = valA - val
460    diffB = valB - val
461    absdA = np.abs(diffA)
462    absdB = np.abs(diffB)
463    #if (diffA/absdA)* (diffB/absdB) < 0.: btw = True
464#    if valA < 0. and valB < 0. and val < 0.:
465#        if (valA >= val and valB < val) or (valA > val and valB <= val): btw =True
466#    else:
467#        if (valA <= val and valB > val) or (valA < val and valB >= val): btw =True
468    if (valA <= val and valB > val) or (valA < val and valB >= val): btw =True
469
470    return btw
471
472def add_secpolygon_list(listv, iip, eep, polygon):
473    """ Function to add a range of points of a polygon into a list
474      listv: list into which add values of the polygon
475      iip: initial value of the range
476      eep: ending value of the range
477      polygon: array with the points of the polygon
478    """
479    fname = 'add_secpolygon_list'
480
481    if eep > iip:
482        for ip in range(iip,eep): listv.append(polygon[ip,:])
483    else:
484        for ip in range(iip,eep,-1): listv.append(polygon[ip,:])
485
486    return
487
488def rm_consecpt_polygon(polygon):
489    """ Function to remove consecutive same point of a polygon
490      poly: polygon
491    >>> poly = np.ones((5,2), dtype=np.float)
492    >>> poly[2,:] = [2., 1.]
493    rm_consecpt_polygon(poly)
494    [[ 1.  1.]
495     [ 2.  1.]
496     [ 1.  1.]]
497    """
498    fname = 'rm_consecpt_polygon'
499
500    newpolygon = []
501    prevpt = polygon[0,:]
502    newpolygon.append(prevpt)
503    for ip in range(1,polygon.shape[0]-1):
504        if polygon[ip,0] != prevpt[0] or polygon[ip,1] != prevpt[1]:
505            prevpt = polygon[ip,:]
506            newpolygon.append(prevpt)
507
508    newpolygon = np.array(newpolygon)
509
510    return newpolygon
511
512def cut_ypolygon(polygon, yval, keep='below', Nadd=20):
513    """ Function to cut a polygon from a given value of the y-axis
514      polygon: polygon to cut
515      yval: value to use to cut the polygon
516      keep: part to keep from the height ('below', default)
517         'below': below the height
518         'above': above the height
519      Nadd: additional points to add to draw the line (20, default)
520    """
521    fname = 'cut_ypolygon'
522
523    N = polygon.shape[0]
524    availkeeps = ['below', 'above']
525
526    if not gen.searchInlist(availkeeps, keep):
527        print errormsg
528        print '  ' + fname + ": wring keep '" + keep + "' value !!"
529        print '    available ones:', availkeeps
530        quit(-1)
531
532    ipt = None
533    ept = None
534
535    # There might be more than 1 cut...
536    Ncuts = 0
537    icut = []
538    ecut = []
539    ipt = []
540    ept = []
541
542    if type(polygon) == type(gen.mamat) and type(polygon.mask) !=                    \
543      type(gen.mamat.mask[1]):
544        # Assuming clockwise polygons
545        for ip in range(N-1):
546            if not polygon.mask[ip,0]:
547                eep = ip + 1
548                if eep == N: eep = 0
549     
550                if val_consec_between(polygon[ip,0], polygon[eep,0], yval):
551                    icut.append(ip)
552                    dx = polygon[eep,1] - polygon[ip,1]
553                    dy = polygon[eep,0] - polygon[ip,0]
554                    dd = yval - polygon[ip,0]
555                    ipt.append([yval, polygon[ip,1]+dx*dd/dy])
556
557                if val_consec_between(polygon[eep,0], polygon[ip,0], yval):
558                    ecut.append(ip)
559                    dx = polygon[eep,1] - polygon[ip,1]
560                    dy = polygon[eep,0] - polygon[ip,0]
561                    dd = yval - polygon[ip,0]
562                    ept.append([yval, polygon[ip,1]+dx*dd/dy])
563                    Ncuts = Ncuts + 1
564    else:
565        # Assuming clockwise polygons
566        for ip in range(N-1):
567            eep = ip + 1
568            if eep == N: eep = 0
569     
570            if val_consec_between(polygon[ip,0], polygon[eep,0], yval):
571                icut.append(ip)
572                dx = polygon[eep,1] - polygon[ip,1]
573                dy = polygon[eep,0] - polygon[ip,0]
574                dd = yval - polygon[ip,0]
575                ipt.append([yval, polygon[ip,1]+dx*dd/dy])
576
577            if val_consec_between(polygon[eep,0], polygon[ip,0], yval):
578                ecut.append(ip)
579                dx = polygon[eep,1] - polygon[ip,1]
580                dy = polygon[eep,0] - polygon[ip,0]
581                dd = yval - polygon[ip,0]
582                ept.append([yval, polygon[ip,1]+dx*dd/dy])
583                Ncuts = Ncuts + 1
584
585    # Looking for repeated
586    newicut = icut + []
587    newecut = ecut + []
588    newipt = ipt + []
589    newept = ept + []
590    newNcuts = Ncuts
591    for ic in range(newNcuts-1):
592        for ic2 in range(ic+1,newNcuts):
593            if newipt[ic] == newipt[ic2]:
594                Ncuts = Ncuts-1
595                icut.pop(ic2)
596                ecut.pop(ic2)
597                ipt.pop(ic2)
598                ept.pop(ic2)
599                newNcuts = Ncuts + 0
600
601    if ipt is None or ept is None or Ncuts == 0:
602        print errormsg
603        print '  ' + fname + ': no cutting for polygon at y=', yval, '!!'
604    else:
605        print '  ' + fname + ': found ', Ncuts, ' Ncuts'
606        if Ncuts > 1 and keep == 'below':
607            # Re-shifting cuts by closest distance.
608            xis = []
609            xes = []
610            for ic in range(Ncuts):
611                xp = ipt[ic]
612                xis.append(xp[1])
613                xp = ept[ic]
614                xes.append(xp[1])
615            xs = xis + xes
616            xs.sort()
617            newicut = icut + []
618            newecut = ecut + []
619            newipt = ipt + []
620            newept = ept + []
621            icut = []
622            ecut = []
623            ipt = []
624            ept = []
625            for xv in xs:
626                ic = xis.count(xv)
627                if ic != 0: 
628                    icc = xis.index(xv)
629                    if len(icut) > len(ecut): 
630                        ecut.append(newicut[icc])
631                        ept.append(newipt[icc])
632                    else: 
633                        icut.append(newicut[icc])
634                        ipt.append(newipt[icc])
635                else:
636                    icc = xes.index(xv)
637                    if len(icut) > len(ecut): 
638                        ecut.append(newecut[icc])
639                        ept.append(newept[icc])
640                    else: 
641                        icut.append(newecut[icc])
642                        ipt.append(newept[icc])
643
644#            # Re-shifting cuts. 1st icut --> last ecut; 1st ecut as 1st icut;
645#            #    2nd icut --> last-1 ecut, ....
646#            newicut = icut + []
647#            newecut = ecut + []
648#            newipt = ipt + []
649#            newept = ept + []
650#            for ic in range(Ncuts-1):
651#                ecut[ic] = newecut[Ncuts-ic-1]
652#                ept[ic] = newept[Ncuts-ic-1]
653#                icut[ic+1] = newecut[ic]
654#                ipt[ic+1] = newept[ic]
655
656#            ecut[Ncuts-1] = newicut[Ncuts-1]
657#            ept[Ncuts-1] = newipt[Ncuts-1]
658
659##        print '    yval=', yval, 'cut, ip; ipt ep; ept ________'
660##        for ic in range(Ncuts):
661##            print '      ', ic, icut[ic], ';', ipt[ic], ecut[ic], ';', ept[ic]
662
663    # Length of joining lines
664    Nadds = []
665    if Ncuts > 1:
666        Naddc = (Nadd-Ncuts)/(Ncuts)
667        if Naddc < 3:
668            print errormsg
669            print '  ' + fname + ': too few points for jioning lines !!'
670            print '    increase Nadd at least to:', Ncuts*3+Ncuts
671            quit(-1)
672        for ic in range(Ncuts-1):
673            Nadds.append(Naddc)
674
675        Nadds.append(Nadd-Naddc*(Ncuts-1))
676    else:
677        Nadds.append(Nadd)
678
679    # Total points cut polygon
680    Ntotpts = 0
681    Ncpts = []
682    for ic in range(Ncuts):
683        if keep == 'below':
684            if ic == 0:
685                dpts = icut[ic] + Nadds[ic] + (N - ecut[ic])
686            else:
687                dpts = ecut[ic] - icut[ic] + Nadds[ic] - 1
688 
689            # Adding end of the polygon in 'left' keeps
690            if ic == Ncuts - 1: dpts = dpts + N-ecut[ic]
691        else:
692            dpts = ecut[ic] - icut[ic] + Nadds[ic] - 1
693
694        Ntotpts = Ntotpts + dpts
695        Ncpts.append(ecut[ic] - icut[ic])
696
697    cutpolygon = np.ones((Ntotpts+Ncuts,2), dtype=np.float)*gen.fillValue
698
699    iipc = 0
700    for ic in range(Ncuts):
701        dcpt = Ncpts[ic]
702        if keep == 'below':
703            if ic == 0:
704                cutpolygon[0:icut[ic],:] = polygon[0:icut[ic],:]
705                iipc = icut[ic]
706            else:
707                cutpolygon[iipc:iipc+dcpt-1,:] = polygon[icut[ic]+1:ecut[ic],:]
708                iipc = iipc + dcpt -1
709        else:
710            cutpolygon[iipc,:] = ipt[ic]
711            cutpolygon[iipc:iipc+dcpt-1,:]=polygon[icut[ic]+1:ecut[ic],:]
712            iipc = iipc+dcpt-1
713
714        # cutting line
715        cutline = np.zeros((Nadds[ic],2), dtype=np.float)
716        dx = (ept[ic][1] - ipt[ic][1])/(Nadds[ic]-1)
717        dy = (ept[ic][0] - ipt[ic][0])/(Nadds[ic]-1)
718        cutline[0,:] = ipt[ic]
719        for ip in range(1,Nadds[ic]-1):
720            cutline[ip,:] = ipt[ic] + np.array([dy*ip,dx*ip])
721        cutline[Nadds[ic]-1,:] = ept[ic]
722        if keep == 'below':
723            if ic == 0: cutpolygon[iipc:iipc+Nadds[ic],:] = cutline
724            else: cutpolygon[iipc:iipc+Nadds[ic],:] = cutline[::-1,:]
725            iipc = iipc+Nadds[ic]
726            if ic == 0:
727                cutpolygon[iipc:iipc+N-ecut[ic]-1,:] = polygon[ecut[ic]+1:N,:]
728                iipc = iipc + N-ecut[ic]-1
729                cutpolygon[iipc,:] = polygon[0,:]
730                iipc = iipc + 1
731        else:
732            cutpolygon[iipc:iipc+Nadds[ic],:] = cutline[::-1,:]
733            iipc = iipc+Nadds[ic]
734        iipc = iipc + 1
735
736    rmpolygon = []
737    Npts = cutpolygon.shape[0]
738    if keep == 'below':
739        for ip in range(Npts):
740            if cutpolygon[ip,0] > yval:
741                rmpolygon.append([gen.fillValueF, gen.fillValueF])
742            else:
743                rmpolygon.append(cutpolygon[ip,:])
744    else:
745        for ip in range(Npts):
746            if cutpolygon[ip,0] < yval:
747                rmpolygon.append([gen.fillValueF, gen.fillValueF])
748            else:
749                rmpolygon.append(cutpolygon[ip,:])
750    Npts = len(rmpolygon)
751    cutpolygon = np.array(rmpolygon)
752
753    cutpolygon = ma.masked_equal(cutpolygon, gen.fillValueF)
754
755    return Npts, cutpolygon
756
757def cut_xpolygon(polygon, xval, keep='left', Nadd=20):
758    """ Function to cut a polygon from a given value of the x-axis
759      polygon: polygon to cut
760      yval: value to use to cut the polygon
761      keep: part to keep from the value ('left', default)
762         'left': left of the value
763         'right': right of the value
764      Nadd: additional points to add to draw the line (20, default)
765    """
766    fname = 'cut_xpolygon'
767
768    N = polygon.shape[0]
769    availkeeps = ['left', 'right']
770
771    if not gen.searchInlist(availkeeps, keep):
772        print errormsg
773        print '  ' + fname + ": wring keep '" + keep + "' value !!"
774        print '    available ones:', availkeeps
775        quit(-1)
776
777    ipt = None
778    ept = None
779
780    # There might be more than 1 cut ...
781    icut = []
782    ecut = []
783    ipt = []
784    ept = []
785    Ncuts = 0
786    if type(polygon) == type(gen.mamat) and type(polygon.mask) !=                    \
787      type(gen.mamat.mask[1]):
788        # Assuming clockwise polygons
789        for ip in range(N-1):
790            if not polygon.mask[ip,1]:
791                eep = ip + 1
792                if eep == N: eep = 0
793     
794                if val_consec_between(polygon[ip,1], polygon[eep,1], xval):
795                    icut.append(ip)
796                    dx = polygon[eep,1] - polygon[ip,1]
797                    dy = polygon[eep,0] - polygon[ip,0]
798                    dd = xval - polygon[ip,1]
799                    ipt.append([polygon[ip,0]+dy*dd/dx, xval])
800
801                if val_consec_between(polygon[eep,1], polygon[ip,1], xval):
802                    ecut.append(ip)
803                    dx = polygon[eep,1] - polygon[ip,1]
804                    dy = polygon[eep,0] - polygon[ip,0]
805                    dd = xval - polygon[ip,1]
806                    ept.append([polygon[ip,0]+dy*dd/dx, xval])
807                    Ncuts = Ncuts + 1
808    else:
809        # Assuming clockwise polygons
810        for ip in range(N-1):
811            eep = ip + 1
812            if eep == N: eep = 0
813     
814            if val_consec_between(polygon[ip,1], polygon[eep,1], xval):
815                icut.append(ip)
816                dx = polygon[eep,1] - polygon[ip,1]
817                dy = polygon[eep,0] - polygon[ip,0]
818                dd = xval - polygon[ip,1]
819                ipt.append([polygon[ip,0]+dy*dd/dx, xval])
820
821            if val_consec_between(polygon[eep,1], polygon[ip,1], xval):
822                ecut.append(ip)
823                dx = polygon[eep,1] - polygon[ip,1]
824                dy = polygon[eep,0] - polygon[ip,0]
825                dd = xval - polygon[ip,1]
826                ept.append([polygon[ip,0]+dy*dd/dx, xval])
827                Ncuts = Ncuts + 1
828
829    # Looking for repeated
830    newicut = icut + []
831    newecut = ecut + []
832    newipt = ipt + []
833    newept = ept + []
834    newNcuts = Ncuts
835    for ic in range(newNcuts-1):
836        for ic2 in range(ic+1,newNcuts):
837            if newipt[ic] == newipt[ic2]:
838                Ncuts = Ncuts-1
839                icut.pop(ic2)
840                ecut.pop(ic2)
841                ipt.pop(ic2)
842                ept.pop(ic2)
843                newNcuts = Ncuts + 0
844
845    if ipt is None or ept is None or Ncuts == 0:
846        print errormsg
847        print '  ' + fname + ': no cutting for polygon at x=', xval, '!!'
848    else:
849        ##print '  ' + fname + ': found ', Ncuts, ' Ncuts'
850        if Ncuts > 1 and keep == 'left':
851            # Re-shifting cuts by closest heigth.
852            yis = []
853            yes = []
854            for ic in range(Ncuts):
855                yp = ipt[ic]
856                yis.append(yp[0])
857                yp = ept[ic]
858                yes.append(yp[0])
859            ys = yis + yes
860            ys.sort()
861            newicut = icut + []
862            newecut = ecut + []
863            newipt = ipt + []
864            newept = ept + []
865            icut = []
866            ecut = []
867            ipt = []
868            ept = []
869            for yv in ys:
870                ic = yis.count(yv)
871                if ic != 0: 
872                    icc = yis.index(yv)
873                    if len(icut) > len(ecut): 
874                        ecut.append(newicut[icc])
875                        ept.append(newipt[icc])
876                    else: 
877                        icut.append(newicut[icc])
878                        ipt.append(newipt[icc])
879                else:
880                    icc = yes.index(yv)
881                    if len(icut) > len(ecut): 
882                        ecut.append(newecut[icc])
883                        ept.append(newept[icc])
884                    else: 
885                        icut.append(newecut[icc])
886                        ipt.append(newept[icc])
887        ##print '    xval=', xval, 'cut, ip; ipt ep; ept ________'
888        ##for ic in range(Ncuts):
889        ##    print '      ', ic, icut[ic], ';', ipt[ic], ecut[ic], ';', ept[ic]
890
891    # Length of joining lines
892    Nadds = []   
893    if Ncuts > 1:
894        Naddc = (Nadd-Ncuts)/(Ncuts)
895        if Naddc < 3:
896            print errormsg
897            print '  ' + fname + ': too few points for jioning lines !!'
898            print '    increase Nadd at least to:', Ncuts*3+Ncuts
899            quit(-1)
900        for ic in range(Ncuts-1):
901            Nadds.append(Naddc)
902
903        Nadds.append(Nadd-Naddc*(Ncuts-1))
904    else:
905        Nadds.append(Nadd)
906
907   # Total points cut polygon
908    Ntotpts = 0
909    Ncpts = []
910    for ic in range(Ncuts):
911        if keep == 'left':
912            if ic == 0: 
913                dpts = icut[ic] + Nadds[ic] + (N - ecut[ic])
914            else:
915                dpts = ecut[ic] - icut[ic] + Nadds[ic] - 1
916
917            # Adding end of the polygon in 'left' keeps
918            if ic == Ncuts - 1: dpts = dpts + N-ecut[ic]
919        else:
920            dpts = ecut[ic] - icut[ic] + Nadds[ic] - 1
921
922        Ntotpts = Ntotpts + dpts
923        Ncpts.append(ecut[ic] - icut[ic])
924
925    cutpolygon = []
926
927    iipc = 0
928    for ic in range(Ncuts):
929        dcpt = Ncpts[ic]
930        if keep == 'left':
931            if ic == 0:
932                add_secpolygon_list(cutpolygon,0,icut[ic],polygon)
933                iipc = icut[ic]
934            else:
935                add_secpolygon_list(cutpolygon,icut[ic]+1,ecut[ic],polygon)
936                #cutpolygon[iipc:iipc+dcpt-1,:] = polygon[icut[ic]+1:ecut[ic],:]
937                iipc = iipc + dcpt -1
938        else:
939            cutpolygon.append(ipt[ic])
940            add_secpolygon_list(cutpolygon,icut[ic]+1,ecut[ic],polygon)
941            #cutpolygon[iipc:iipc+dcpt-1,:]=polygon[icut[ic]+1:ecut[ic],:]
942            iipc = iipc+dcpt-1
943
944        # cutting line
945        cutline = np.zeros((Nadds[ic],2), dtype=np.float)
946        dx = (ept[ic][1] - ipt[ic][1])/(Nadds[ic]-1)
947        dy = (ept[ic][0] - ipt[ic][0])/(Nadds[ic]-1)
948        cutline[0,:] = ipt[ic]
949        for ip in range(1,Nadds[ic]-1):
950            cutline[ip,:] = ipt[ic] + np.array([dy*ip,dx*ip])
951        cutline[Nadds[ic]-1,:] = ept[ic]
952        print 'Lluis ipt0', ipt[ic], 'cutline[Nadds-ic,:]', cutline[Nadds[ic]-1,:], 'ept', ept[ic]
953        if keep == 'left':
954            if ic == 0: 
955                for ip in range(Nadds[ic]): cutpolygon.append(cutline[ip,:])
956            else: 
957                for ip in range(Nadds[ic]-1,0,-1): cutpolygon.append(cutline[ip,:])
958            iipc = iipc+Nadds[ic]
959            if ic == 0:
960#                cutpolygon[iipc:iipc+N-ecut[ic]-1,:] = polygon[ecut[ic]+1:N,:]
961#                iipc = iipc + N-ecut[ic]-1
962                add_secpolygon_list(cutpolygon,ecut[ic]-2,N,polygon)
963                #cutpolygon[iipc:iipc+N-ecut[ic]+2,:] = polygon[ecut[ic]-2:N,:]
964                iipc = iipc + N-ecut[ic]+2
965                cutpolygon.append(polygon[0,:])
966                iipc = iipc + 1
967        else:
968            for ip in range(Nadds[ic]-1,0,-1): cutpolygon.append(cutline[ip,:])
969            iipc = iipc+Nadds[ic]
970        cutpolygon.append([gen.fillValueF, gen.fillValueF])
971        iipc = iipc + 1
972
973    cutpolygon = np.array(cutpolygon)
974    rmpolygon = []
975    Npts = cutpolygon.shape[0]
976    if keep == 'left':
977        for ip in range(Npts):
978            if cutpolygon[ip,1] > xval:
979                rmpolygon.append([gen.fillValueF, gen.fillValueF])
980            else:
981                rmpolygon.append(cutpolygon[ip,:])
982    else:
983        for ip in range(Npts):
984            if cutpolygon[ip,1] < xval:
985                rmpolygon.append([gen.fillValueF, gen.fillValueF])
986            else:
987                rmpolygon.append(cutpolygon[ip,:])
988    Npts = len(rmpolygon)
989
990    rmpolygon = np.array(rmpolygon)
991    cutpolygon = rm_consecpt_polygon(rmpolygon)
992
993    cutpolygon = ma.masked_equal(cutpolygon, gen.fillValueF)
994
995    return Npts, cutpolygon
996
997def cut_between_ypolygon(polygon, yval1, yval2, Nadd=20):
998    """ Function to cut a polygon between 2 given value of the y-axis
999      polygon: polygon to cut
1000      yval1: first value to use to cut the polygon
1001      yval2: first value to use to cut the polygon
1002      Nadd: additional points to add to draw the line (20, default)
1003    """
1004    fname = 'cut_betwen_ypolygon'
1005
1006    N = polygon.shape[0]
1007
1008    if yval1 > yval2:
1009        print errormsg
1010        print '  ' + fname + ': wrong between cut values !!'
1011        print '     it is expected yval1 < yval2'
1012        print '     values provided yval1: (', yval1, ')> yval2 (', yval2, ')'
1013        quit(-1)
1014
1015    yvals = [yval1, yval2]
1016
1017    ipt = None
1018    ept = None
1019
1020    cuts = {}
1021    if type(polygon) == type(gen.mamat) and type(polygon.mask) !=                    \
1022      type(gen.mamat.mask[1]):
1023        for ic in range(2):
1024            yval = yvals[ic]
1025            # There might be more than 1 cut ...
1026            icut = []
1027            ecut = []
1028            ipt = []
1029            ept = []
1030            Ncuts = 0
1031            # Assuming clockwise polygons
1032            for ip in range(N-1):
1033                if not polygon.mask[ip,0]:
1034                    eep = ip + 1
1035                    if eep == N: eep = 0
1036     
1037                    if val_consec_between(polygon[ip,0], polygon[eep,0], yval):
1038                        icut.append(ip)
1039                        dx = polygon[eep,1] - polygon[ip,1]
1040                        dy = polygon[eep,0] - polygon[ip,0]
1041                        dd = yval - polygon[ip,0]
1042                        ipt.append([yval, polygon[ip,1]+dx*dd/dy])
1043
1044                    if val_consec_between(polygon[eep,0], polygon[ip,0], yval):
1045                        ecut.append(ip)
1046                        dx = polygon[eep,1] - polygon[ip,1]
1047                        dy = polygon[eep,0] - polygon[ip,0]
1048                        dd = yval - polygon[ip,0]
1049                        ept.append([yval, polygon[ip,1]+dx*dd/dy])
1050                        Ncuts = Ncuts + 1
1051
1052            # Looking for repeated
1053            newicut = icut + []
1054            newecut = ecut + []
1055            newipt = ipt + []
1056            newept = ept + []
1057            newNcuts = Ncuts
1058            for icp in range(newNcuts-1):
1059                for ic2 in range(icp+1,newNcuts):
1060                    if newipt[icp] == newipt[ic2]:
1061                        Ncuts = Ncuts-1
1062                        icut.pop(ic2)
1063                        ecut.pop(ic2)
1064                        ipt.pop(ic2)
1065                        ept.pop(ic2)
1066                        newNcuts = Ncuts + 0
1067
1068            cuts[ic] = [icut, ecut, ipt, ept, Ncuts]
1069    else:
1070        for ic in range(2):
1071            yval = yvals[ic]
1072            # There might be more than 1 cut ...
1073            icut = []
1074            ecut = []
1075            ipt = []
1076            ept = []
1077            Ncuts = 0
1078            # Assuming clockwise polygons
1079            for ip in range(N-1):
1080                eep = ip + 1
1081                if eep == N: eep = 0
1082     
1083                if val_consec_between(polygon[ip,0], polygon[eep,0], yval):
1084                    icut.append(ip)
1085                    dx = polygon[eep,1] - polygon[ip,1]
1086                    dy = polygon[eep,0] - polygon[ip,0]
1087                    dd = yval - polygon[ip,0]
1088                    ipt.append([yval, polygon[ip,1]+dx*dd/dy])
1089
1090                if val_consec_between(polygon[eep,0], polygon[ip,0], yval):
1091                    ecut.append(ip)
1092                    dx = polygon[eep,1] - polygon[ip,1]
1093                    dy = polygon[eep,0] - polygon[ip,0]
1094                    dd = yval - polygon[ip,0]
1095                    ept.append([yval, polygon[ip,1]+dx*dd/dy])
1096                    Ncuts = Ncuts + 1
1097            # Looking for repeated
1098            newicut = icut + []
1099            newecut = ecut + []
1100            newipt = ipt + []
1101            newept = ept + []
1102            newNcuts = Ncuts
1103            for icp in range(newNcuts-1):
1104                for ic2 in range(icp+1,newNcuts):
1105                    if newipt[icp] == newipt[ic2]:
1106                        Ncuts = Ncuts-1
1107                        icut.pop(ic2)
1108                        ecut.pop(ic2)
1109                        ipt.pop(ic2)
1110                        ept.pop(ic2)
1111                        newNcuts = Ncuts + 0
1112
1113            cuts[ic] = [icut, ecut, ipt, ept, Ncuts]
1114
1115    Naddlines = {}
1116    for icc in range(2):
1117        cutv = cuts[icc]
1118        Ncuts = cutv[4]
1119        # Length of joining lines
1120        Nadds = []
1121        if Ncuts > 1:
1122            Naddc = (Nadd-Ncuts)/(Ncuts)
1123            if Naddc < 3:
1124                print errormsg
1125                print '  ' + fname + ': too few points for jioning lines !!'
1126                print '    increase Nadd at least to:', Ncuts*3+Ncuts
1127                quit(-1)
1128            for ic in range(Ncuts-1):
1129                Nadds.append(Naddc)
1130
1131            Nadds.append(Nadd-Naddc*(Ncuts-1))
1132        else:
1133            Nadds.append(Nadd)
1134
1135        # Total points cut polygon
1136        Ntotpts = 0
1137        Ncpts = []
1138        for ic in range(Ncuts):
1139            dpts = ecut[ic] - icut[ic] + Nadds[ic] - 1
1140
1141            Ntotpts = Ntotpts + dpts
1142            Ncpts.append(ecut[ic] - icut[ic])
1143
1144        Naddlines[icc] = [Nadds, Ntotpts, Ncpts]
1145
1146    cutv1 = cuts[0]
1147    addv1 = Naddlines[0]
1148    Nadds1 = addv1[0]
1149    Ncuts1 = cutv1[4]
1150
1151    cutv2 = cuts[1]
1152    addv2 = Naddlines[1]
1153    Nadds2 = addv2[0]
1154    Ncuts2 = cutv2[4]
1155
1156    if Ncuts1 != Ncuts2: 
1157        print errormsg
1158        print '  ' + fname + ": different number of cuts !!"
1159        print '    yval1:', yval1, 'Ncuts=', Ncuts1
1160        print '    yval2:', yval2, 'Ncuts=', Ncuts2
1161        print '      I am not prepare to deal with it'
1162        quit(-1)
1163    #else:
1164    #    print '  ' + fname + ' _______'
1165    #    print '    yval1:', yval1, 'Ncuts=', Ncuts1
1166    #    print '    yval2:', yval2, 'Ncuts=', Ncuts2
1167
1168    icut1 = cutv1[0]
1169    ecut1 = cutv1[1]
1170    ipt1 = cutv1[2]
1171    ept1 = cutv1[3]
1172    icut2 = cutv2[0]
1173    ecut2 = cutv2[1]
1174    ipt2 = cutv2[2]
1175    ept2 = cutv2[3]
1176
1177    # Looking for pairs of cuts. Grouping for smallest x distance between initial   
1178    #   points of each cut
1179    cutpolygons = []
1180    for iic1 in range(Ncuts1):
1181        iip = 0
1182        cutpolygon = []
1183        ic1 = icut1[iic1]
1184        ec1 = ecut1[iic1]
1185        ip1 = ipt1[iic1]
1186        ep1 = ept1[iic1]
1187
1188        ipx2s = []
1189        for ip in range(Ncuts2): 
1190            ip2 = ipt2[ip]
1191            ipx2s.append(ip2[1])
1192        dxps = ipx2s - ip1[1]
1193        dxps = np.where(dxps < 0., gen.fillValueF, dxps)
1194        ndxps = np.min(dxps)
1195        iic12 = gen.index_vec(dxps,ndxps)
1196
1197        ic2 = icut2[iic12]
1198        ec2 = ecut2[iic12]
1199        ip2 = ipt2[iic12]
1200        ep2 = ept2[iic12]
1201
1202        #print 'Lluis iic1', iic1, 'ic1', ic1, 'ec1', ec1, 'ipt1', ip1, 'ept1', ep1, 'Nadds1', Nadds1
1203        #print '    iic12', iic12, 'ic2', ic2, 'ec2', ec2, 'ipt2', ip2, 'ept2', ep2, 'Nadds2', Nadds2
1204
1205        cutpolygon.append(ip1)
1206        for ip in range(ic1+1,ic2-1):
1207            cutpolygon.append(polygon[ip,:])
1208        iip = ic2-ic1
1209        # cutting line 1
1210        Nadd2 = Nadds1[iic1]
1211        cutlines = np.zeros((Nadd2,2), dtype=np.float)
1212        dx = (ep2[1] - ip2[1])/(Nadd2-2)
1213        dy = (ep2[0] - ip2[0])/(Nadd2-2)
1214        cutlines[0,:] = ip2
1215        for ip in range(1,Nadd2-1):
1216            cutlines[ip,:] = ip2 + np.array([dy*ip,dx*ip])
1217        cutlines[Nadd2-1,:] = ep2
1218        for ip in range(Nadd2): cutpolygon.append(cutlines[ip,:])
1219        iip = iip + Nadd2
1220
1221        for ip in range(ec2,ec1):
1222            cutpolygon.append(polygon[ip,:])
1223        iip = iip + ec1-ec2
1224        # cutting line 2
1225        Nadd2 = Nadds2[iic12]
1226        cutlines = np.zeros((Nadd2,2), dtype=np.float)
1227        dx = (ep1[1] - ip1[1])/(Nadd2-2)
1228        dy = (ep1[0] - ip1[0])/(Nadd2-2)
1229        cutlines[0,:] = ip1
1230        for ip in range(1,Nadd2-1):
1231            cutlines[ip,:] = ip1 + np.array([dy*ip,dx*ip])
1232        cutlines[Nadd2-1,:] = ep1
1233        for ip in range(Nadd2-1,0,-1):
1234            cutpolygon.append(cutlines[ip,:])
1235
1236        cutpolygon.append(ip1)
1237
1238        cutpolygon.append([gen.fillValueF,gen.fillValueF])
1239        if len(cutpolygons) == 0: cutpolygons = cutpolygon
1240        else: cutpolygons = cutpolygons + cutpolygon
1241
1242    cutpolygons = np.array(cutpolygons)
1243    cutpolygons = ma.masked_equal(cutpolygons, gen.fillValueF)
1244
1245    Npts = cutpolygons.shape[0]
1246
1247    return Npts, cutpolygons
1248
1249def cut_between_xpolygon(polygon, xval1, xval2, Nadd=20):
1250    """ Function to cut a polygon between 2 given value of the x-axis
1251      polygon: polygon to cut
1252      xval1: first value to use to cut the polygon
1253      xval2: first value to use to cut the polygon
1254      Nadd: additional points to add to draw the line (20, default)
1255    """
1256    fname = 'cut_betwen_xpolygon'
1257
1258    N = polygon.shape[0]
1259
1260    if xval1 > xval2:
1261        print errormsg
1262        print '  ' + fname + ': wrong between cut values !!'
1263        print '     it is expected xval1 < xval2'
1264        print '     values provided xval1: (', xval1, ')> xval2 (', xval2, ')'
1265        quit(-1)
1266
1267    xvals = [xval1, xval2]
1268
1269    ipt = None
1270    ept = None
1271
1272    cuts = {}
1273    if type(polygon) == type(gen.mamat) and type(polygon.mask) !=                    \
1274      type(gen.mamat.mask[1]):
1275        for ic in range(2):
1276            xval = xvals[ic]
1277            # There might be more than 1 cut ...
1278            icut = []
1279            ecut = []
1280            ipt = []
1281            ept = []
1282            Ncuts = 0
1283            # Assuming clockwise polygons
1284            for ip in range(N-1):
1285                if not polygon.mask[ip,0]:
1286                    eep = ip + 1
1287                    if eep == N: eep = 0
1288     
1289                    if val_consec_between(polygon[ip,1], polygon[eep,1], xval):
1290                        icut.append(ip)
1291                        dx = polygon[eep,1] - polygon[ip,1]
1292                        dy = polygon[eep,0] - polygon[ip,0]
1293                        dd = xval - polygon[ip,1]
1294                        ipt.append([polygon[ip,0]+dy*dd/dx, xval])
1295
1296                    if val_consec_between(polygon[eep,1], polygon[ip,1], xval):
1297                        ecut.append(ip)
1298                        dx = polygon[eep,1] - polygon[ip,1]
1299                        dy = polygon[eep,0] - polygon[ip,0]
1300                        dd = xval - polygon[ip,1]
1301                        ept.append([polygon[ip,0]+dy*dd/dx, xval])
1302                        Ncuts = Ncuts + 1
1303
1304            # Looking for repeated
1305            newicut = icut + []
1306            newecut = ecut + []
1307            newipt = ipt + []
1308            newept = ept + []
1309            newNcuts = Ncuts
1310            for icp in range(newNcuts-1):
1311                for ic2 in range(icp+1,newNcuts):
1312                    if newipt[icp] == newipt[ic2]:
1313                        Ncuts = Ncuts-1
1314                        icut.pop(ic2)
1315                        ecut.pop(ic2)
1316                        ipt.pop(ic2)
1317                        ept.pop(ic2)
1318                        newNcuts = Ncuts + 0
1319
1320            cuts[ic] = [icut, ecut, ipt, ept, Ncuts]
1321    else:
1322        for ic in range(2):
1323            xval = xvals[ic]
1324            # There might be more than 1 cut ...
1325            icut = []
1326            ecut = []
1327            ipt = []
1328            ept = []
1329            Ncuts = 0
1330            # Assuming clockwise polygons
1331            for ip in range(N-1):
1332                eep = ip + 1
1333                if eep == N: eep = 0
1334     
1335                if val_consec_between(polygon[ip,1], polygon[eep,1], xval):
1336                    icut.append(ip)
1337                    dx = polygon[eep,1] - polygon[ip,1]
1338                    dy = polygon[eep,0] - polygon[ip,0]
1339                    dd = xval - polygon[ip,1]
1340                    ipt.append([polygon[ip,0]+dy*dd/dx, xval])
1341
1342                if val_consec_between(polygon[eep,1], polygon[ip,1], xval):
1343                    ecut.append(ip)
1344                    dx = polygon[eep,1] - polygon[ip,1]
1345                    dy = polygon[eep,0] - polygon[ip,0]
1346                    dd = xval - polygon[ip,1]
1347                    ept.append([polygon[ip,0]+dy*dd/dx, xval])
1348                    Ncuts = Ncuts + 1
1349            # Looking for repeated
1350            newicut = icut + []
1351            newecut = ecut + []
1352            newipt = ipt + []
1353            newept = ept + []
1354            newNcuts = Ncuts
1355            for icp in range(newNcuts-1):
1356                for ic2 in range(icp+1,newNcuts):
1357                    if newipt[icp] == newipt[ic2]:
1358                        Ncuts = Ncuts-1
1359                        icut.pop(ic2)
1360                        ecut.pop(ic2)
1361                        ipt.pop(ic2)
1362                        ept.pop(ic2)
1363                        newNcuts = Ncuts + 0
1364
1365            cuts[ic] = [icut, ecut, ipt, ept, Ncuts]
1366
1367    for iic in range(1):
1368        cutvs = cuts[iic]
1369        icut = cutvs[0]
1370        ecut = cutvs[1]
1371        ipt = cutvs[2]
1372        ept = cutvs[3]
1373        Ncuts = cutvs[4]
1374        if Ncuts > 0:
1375            # Re-shifting cuts by closest heigth.
1376            yis = []
1377            yes = []
1378            for ic in range(Ncuts):
1379                yp = ipt[ic]
1380                yis.append(yp[0])
1381                yp = ept[ic]
1382                yes.append(yp[0])
1383            ys = yis + yes
1384            ys.sort()
1385            newicut = icut + []
1386            newecut = ecut + []
1387            newipt = ipt + []
1388            newept = ept + []
1389            icut = []
1390            ecut = []
1391            ipt = []
1392            ept = []
1393            for yv in ys:
1394                ic = yis.count(yv)
1395                if ic != 0: 
1396                    icc = yis.index(yv)
1397                    if len(icut) > len(ecut): 
1398                        ecut.append(newicut[icc])
1399                        ept.append(newipt[icc])
1400                    else: 
1401                        icut.append(newicut[icc])
1402                        ipt.append(newipt[icc])
1403                else:
1404                    icc = yes.index(yv)
1405                    if len(icut) > len(ecut): 
1406                        ecut.append(newecut[icc])
1407                        ept.append(newept[icc])
1408                    else: 
1409                        icut.append(newecut[icc])
1410                        ipt.append(newept[icc])
1411
1412        cuts[iic] = [icut, ecut, ipt, ept, Ncuts]
1413
1414    Naddlines = {}
1415    for icc in range(2):
1416        cutv = cuts[icc]
1417        Ncuts = cutv[4]
1418        if Ncuts == 0:
1419            print errormsg
1420            print '  ' + fname + ": no cuts for xval=", xvals[icc], '!!'
1421            quit(-1)
1422        #print '  icc:', icc, 'ic ec ipt ept _______'
1423        #for ic in range(Ncuts):
1424        #    print ic, ':', cutv[0][ic], cutv[1][ic], cutv[2][ic], cutv[3][ic]
1425
1426        # Length of joining lines
1427        Nadds = []
1428        if Ncuts > 1:
1429            Naddc = (Nadd-Ncuts)/(Ncuts)
1430            if Naddc < 3:
1431                print errormsg
1432                print '  ' + fname + ': too few points for jioning lines !!'
1433                print '    increase Nadd at least to:', Ncuts*3+Ncuts
1434                quit(-1)
1435            for ic in range(Ncuts-1):
1436                Nadds.append(Naddc)
1437
1438            Nadds.append(Nadd-Naddc*(Ncuts-1))
1439        else:
1440            Nadds.append(Nadd)
1441
1442        Naddlines[icc] = Nadds
1443
1444    # sides
1445    sides = {}
1446    for iic in range(2):
1447        cutvs = cuts[iic]
1448        icut = cutvs[0]
1449        ecut = cutvs[1]
1450        ipt = cutvs[2]
1451        ept = cutvs[3]
1452        Ncuts = cutvs[4]
1453        Nadds = Naddlines[iic]
1454        cutpolygon = []
1455        # left side
1456        if iic == 0:
1457            for ic in range(Ncuts-1):
1458                cutpolygon.append(ipt[ic])
1459                dx = (ept[ic][1] - ipt[ic][1])/(Nadds[ic]-1)
1460                dy = (ept[ic][0] - ipt[ic][0])/(Nadds[ic]-1)
1461                for ip in range(1,Nadds[ic]-1):
1462                    cutpolygon.append([ipt[ic][0]+dy*ip, ipt[ic][1]+dx*ip])
1463                cutpolygon.append(ept[ic])
1464                for ip in range(ecut[ic]+1,icut[ic+1]): cutpolygon.append(polygon[ip,:])
1465
1466            print 'Lluis ', Ncuts, 'ic', Ncuts-1
1467            ic = Ncuts-1
1468            cutpolygon.append(ipt[ic])
1469            dx = (ept[ic][1] - ipt[ic][1])/(Nadds[ic]-1)
1470            dy = (ept[ic][0] - ipt[ic][0])/(Nadds[ic]-1)
1471            for ip in range(1,Nadds[ic]-1):
1472                cutpolygon.append([ipt[ic][0]+dy*ip, ipt[ic][1]+dx*ip])
1473        # right side
1474        else:
1475            for ic in range(Ncuts-1):
1476                cutpolygon.append(ipt[ic])
1477
1478                # line
1479                dx = (ept[ic][1] - ipt[ic][1])/(Nadds[ic]-1)
1480                dy = (ept[ic][0] - ipt[ic][0])/(Nadds[ic]-1)
1481                for ip in range(1,Nadds[ic]-1):
1482                    cutpolygon.append([ipt[ic][0]+dy*ip, ipt[ic][1]+dx*ip])
1483                cutpolygon.append(ept[ic])
1484                for ip in range(ecut[ic],icut[ic+1]): cutpolygon.append(polygon[ip,:])
1485
1486            ic = Ncuts-1
1487            cutpolygon.append(ipt[ic])
1488            # line
1489            dx = (ept[ic][1] - ipt[ic][1])/(Nadds[ic]-1)
1490            dy = (ept[ic][0] - ipt[ic][0])/(Nadds[ic]-1)
1491            for ip in range(1,Nadds[ic]-1):
1492                cutpolygon.append([ipt[ic][0]+dy*ip, ipt[ic][1]+dx*ip])
1493            cutpolygon.append(ept[ic])
1494        sides[iic] = cutpolygon
1495       
1496    # joining sides by e1[Ncuts1-1] --> i2[0]; e2[Ncuts2-1] --> i1[0]
1497    cutv1 = cuts[0]
1498    Ncuts1 = cutv1[4]
1499    ec1 = cutv1[1][np.max([0,Ncuts1-1])]
1500    ic1 = cutv1[0][0]
1501    ept1 = cutv1[3][np.max([0,Ncuts1-1])]
1502    ipt1 = cutv1[2][0]
1503
1504    cutv2 = cuts[1]
1505    Ncuts2 = cutv2[4]
1506    ec2 = cutv2[1][np.max([0,Ncuts2-1])]
1507    ic2 = cutv2[0][0]
1508    ept2 = cutv2[3][np.max([0,Ncuts2-1])]
1509    ipt2 = cutv2[2][0]
1510
1511    finalcutpolygon = sides[0]
1512    for ip in range(ec1+1,ic2): finalcutpolygon.append(polygon[ip,:])
1513    finalcutpolygon = finalcutpolygon + sides[1]
1514    for ip in range(ec2+1,ic1): finalcutpolygon.append(polygon[ip,:])
1515    finalcutpolygon.append(ipt1)
1516
1517    finalcutpolygon = np.array(finalcutpolygon)
1518    finalcutpolygon = ma.masked_equal(finalcutpolygon, gen.fillValueF)
1519
1520    Npts = finalcutpolygon.shape[0]
1521
1522    return Npts, finalcutpolygon
1523
1524def cut_between_xpolygon_old(polygon, xval1, xval2, Nadd=20):
1525    """ Function to cut a polygon between 2 given value of the x-axis
1526      polygon: polygon to cut
1527      xval1: first value to use to cut the polygon
1528      xval2: first value to use to cut the polygon
1529      Nadd: additional points to add to draw the line (20, default)
1530    """
1531    fname = 'cut_betwen_xpolygon'
1532
1533    N = polygon.shape[0]
1534
1535    ipt = None
1536    ept = None
1537
1538    dx = np.zeros((2), dtype=np.float)
1539    dy = np.zeros((2), dtype=np.float)
1540    icut = np.zeros((2), dtype=int)
1541    ecut = np.zeros((2), dtype=int)
1542    ipt = np.zeros((2,2), dtype=np.float)
1543    ept = np.zeros((2,2), dtype=np.float)
1544
1545    if xval1 > xval2:
1546        print errormsg
1547        print '  ' + fname + ': wrong between cut values !!'
1548        print '     it is expected xval1 < xval2'
1549        print '     values provided xval1: (', xval1, ')> xval2 (', xval2, ')'
1550        quit(-1)
1551
1552    xvals = [xval1, xval2]
1553
1554    for ic in range(2):
1555        xval = xvals[ic]
1556        if type(polygon) == type(gen.mamat):
1557            # Assuming clockwise polygons
1558            for ip in range(N-1):
1559                if not polygon.mask[ip,0]:
1560                    eep = ip + 1
1561                    if eep == N: eep = 0
1562     
1563                    if (polygon[ip,1] <= xval and polygon[eep,1] > xval) or          \
1564                      (polygon[ip,1] < xval and polygon[eep,1] >= xval):
1565                        icut[ic] = ip
1566                        dx[ic] = polygon[eep,1] - polygon[ip,1]
1567                        dy[ic] = polygon[eep,0] - polygon[ip,0]
1568                        dd = xval - polygon[ip,1]
1569                        ipt[ic,:] = [polygon[ip,0]+dy[ic]*dd/dx[ic], xval]
1570
1571                    if (polygon[ip,1] >= yval and polygon[eep,1] < xval) or          \
1572                      (polygon[ip,1] > yval and polygon[eep,1] <= xval):
1573                        ecut[ic] = ip
1574                        dx[ic] = polygon[eep,1] - polygon[ip,1]
1575                        dy[ic] = polygon[eep,0] - polygon[ip,0]
1576                        dd = xval - polygon[ip,1]
1577                        ept[ic,:] = [polygon[ip,0]+dy[ic]*dd/dx[ic], xval]
1578        else:
1579            # Assuming clockwise polygons
1580            for ip in range(N-1):
1581                eep = ip + 1
1582                if eep == N: eep = 0
1583     
1584                if (polygon[ip,1] <= xval and polygon[eep,1] > xval) or              \
1585                  (polygon[ip,1] < xval and polygon[eep,1] >= xval):
1586                    icut[ic] = ip
1587                    dx[ic] = polygon[eep,1] - polygon[ip,1]
1588                    dy[ic] = polygon[eep,0] - polygon[ip,0]
1589                    dd = xval - polygon[ip,1]
1590                    print 'Lluis ip', ip, 'poly:', polygon[ip,:], 'xval:', xval, 'ip+1', polygon[eep,:]
1591                    print '  dx:', dx, 'dy:', dy, 'dd', dd
1592                    ipt[ic,:] = [polygon[ip,0]+dy[ic]*dd/dx[ic], xval]
1593
1594                if (polygon[ip,1] >= xval and polygon[eep,1] < xval) or              \
1595                  (polygon[ip,1] > xval and polygon[eep,1] <= xval):
1596                    ecut[ic] = ip
1597                    dx[ic] = polygon[eep,1] - polygon[ip,1]
1598                    dy[ic] = polygon[eep,0] - polygon[ip,0]
1599                    dd = xval - polygon[ip,1]
1600                    if dx[ic] == 0.:
1601                        ept[ic,:] = [polygon[eep,0], xval]
1602                    else:
1603                        ept[ic,:] = [polygon[ip,0]+dy[ic]*dd/dx[ic], xval]
1604
1605        if ipt is None or ept is None:
1606            print errormsg
1607            print '  ' + fname + ': no cutting for polygon at x=', xval, '!!'
1608
1609    Npts = icut[1] - icut[0] + Nadd + ecut[0] - ecut[1]
1610    cutpolygon = np.zeros((Npts,2), dtype=np.float)
1611    cutpolygon[0,:] = ipt[0,:]
1612    cutpolygon[1:icut[1]-icut[0]+1,:] = polygon[icut[0]+1:icut[1]+1,:]
1613    iip = icut[1]-icut[0]
1614
1615    # cutting lines
1616    Nadd2 = int(Nadd/2)
1617    cutlines = np.zeros((2,Nadd2,2), dtype=np.float)
1618
1619    for ic in range(2):
1620        print ic, 'Lluis ipt:', ipt[ic,:], 'ept:', ept[ic,:]
1621        dx = (ept[ic,1] - ipt[ic,1])/(Nadd2-2)
1622        dy = (ept[ic,0] - ipt[ic,0])/(Nadd2-2)
1623        print '    dx:', dx, 'dy', dy
1624        cutlines[ic,0,:] = ipt[ic,:]
1625        for ip in range(1,Nadd2-1):
1626            cutlines[ic,ip,:] = ipt[ic,:] + np.array([dy*ip,dx*ip])
1627        cutlines[ic,Nadd2-1,:] = ept[ic,:]
1628
1629    cutpolygon[iip:iip+Nadd2,:] = cutlines[1,:,:]
1630    iip = iip + Nadd2
1631    cutpolygon[iip:iip+(ecut[0]-ecut[1]),:] = polygon[ecut[1]+1:ecut[0]+1,:]
1632    iip = iip + ecut[0]-ecut[1]
1633    cutpolygon[iip:iip+Nadd2,:] = cutlines[0,::-1,:]
1634
1635    cutpolygon = ma.masked_equal(cutpolygon, gen.fillValueF)
1636
1637    return Npts, cutpolygon
1638
1639####### ###### ##### #### ### ## #
1640# Shapes/objects
1641
1642def surface_sphere(radii,Npts):
1643    """ Function to provide an sphere as matrix of x,y,z coordinates
1644      radii: radii of the sphere
1645      Npts: number of points to discretisize longitues (half for latitudes)
1646    """
1647    fname = 'surface_sphere'
1648
1649    sphereup = np.zeros((3,Npts/2,Npts), dtype=np.float)
1650    spheredown = np.zeros((3,Npts/2,Npts), dtype=np.float)
1651    for ia in range(Npts):
1652        alpha = ia*2*np.pi/(Npts-1)
1653        for ib in range(Npts/2):
1654            beta = ib*np.pi/(2.*(Npts/2-1))
1655            sphereup[:,ib,ia] = position_sphere(radii, alpha, beta)
1656        for ib in range(Npts/2):
1657            beta = -ib*np.pi/(2.*(Npts/2-1))
1658            spheredown[:,ib,ia] = position_sphere(radii, alpha, beta)
1659
1660    return sphereup, spheredown
1661
1662def ellipse_polar(c, a, b, Nang=100):
1663    """ Function to determine an ellipse from its center and polar coordinates
1664        FROM: https://en.wikipedia.org/wiki/Ellipse
1665      c= coordinates of the center
1666      a= distance major axis
1667      b= distance minor axis
1668      Nang= number of angles to use
1669    """
1670    fname = 'ellipse_polar'
1671
1672    if np.mod(Nang,2) == 0: Nang=Nang+1
1673 
1674    dtheta = 2*np.pi/(Nang-1)
1675
1676    ellipse = np.zeros((Nang,2), dtype=np.float)
1677    for ia in range(Nang):
1678        theta = dtheta*ia
1679        rad = a*b/np.sqrt( (b*np.cos(theta))**2 + (a*np.sin(theta))**2 )
1680        x = rad*np.cos(theta)
1681        y = rad*np.sin(theta)
1682        ellipse[ia,:] = [y+c[0],x+c[1]]
1683
1684    return ellipse
1685
1686def hyperbola_polar(a, b, Nang=100):
1687    """ Fcuntion to determine an hyperbola in polar coordinates
1688        FROM: https://en.wikipedia.org/wiki/Hyperbola#Polar_coordinates
1689          x^2/a^2 - y^2/b^2 = 1
1690      a= x-parameter
1691      y= y-parameter
1692      Nang= number of angles to use
1693      DOES NOT WORK!!!!
1694    """
1695    fname = 'hyperbola_polar'
1696
1697    dtheta = 2.*np.pi/(Nang-1)
1698
1699    # Positive branch
1700    hyperbola_p = np.zeros((Nang,2), dtype=np.float)
1701    for ia in range(Nang):
1702        theta = dtheta*ia
1703        x = a*np.cosh(theta)
1704        y = b*np.sinh(theta)
1705        hyperbola_p[ia,:] = [y,x]
1706
1707    # Negative branch
1708    hyperbola_n = np.zeros((Nang,2), dtype=np.float)
1709    for ia in range(Nang):
1710        theta = dtheta*ia
1711        x = -a*np.cosh(theta)
1712        y = b*np.sinh(theta)
1713        hyperbola_n[ia,:] = [y,x]
1714
1715    return hyperbola_p, hyperbola_n
1716
1717def circ_sec(ptA, ptB, radii, arc='short', pos='left', Nang=100):
1718    """ Function union of point A and B by a section of a circle
1719      ptA= coordinates od the point A [yA, xA]
1720      ptB= coordinates od the point B [yB, xB]
1721      radii= radi of the circle to use to unite the points
1722      arc= which arc to be used ('short', default)
1723        'short': shortest angle between points
1724        'long': largest angle between points
1725      pos= orientation of the arc following clockwise union of points ('left', default)
1726        'left': to the left of union
1727        'right': to the right of union
1728      Nang= amount of angles to use
1729    """
1730    fname = 'circ_sec'
1731    availarc = ['short', 'long']
1732    availpos = ['left', 'right']
1733
1734    distAB = dist_points(ptA,ptB)
1735
1736    if distAB > radii:
1737        print errormsg
1738        print '  ' + fname + ': radii=', radii, " too small for the distance " +     \
1739          "between points !!"
1740        print '    distance between points:', distAB
1741        quit(-1)
1742
1743    # Coordinate increments
1744    dAB = np.abs(ptA-ptB)
1745
1746    # angle of the circular section joining points
1747    alpha = 2.*np.arcsin((distAB/2.)/radii)
1748
1749    # center along coincident bisection of the union
1750    xcc = -radii
1751    ycc = 0.
1752
1753    # Getting the arc of the circle at the x-axis
1754    if arc == 'short':
1755        dalpha = alpha/(Nang-1)
1756    elif arc == 'long':
1757        dalpha = (2.*np.pi - alpha)/(Nang-1)
1758    else:
1759        print errormsg
1760        print '  ' + fname + ": arc '" + arc + "' not ready !!" 
1761        print '    available ones:', availarc
1762        quit(-1)
1763    if pos == 'left': sign=-1.
1764    elif pos == 'right': sign=1.
1765    else:
1766        print errormsg
1767        print '  ' + fname + ": position '" + pos + "' not ready !!" 
1768        print '     available ones:', availpos
1769        quit(-1)
1770
1771    circ_sec = np.zeros((Nang,2), dtype=np.float)
1772    for ia in range(Nang):
1773        alpha = sign*dalpha*ia
1774        x = radii*np.cos(alpha)
1775        y = radii*np.sin(alpha)
1776
1777        circ_sec[ia,:] = [y+ycc,x+xcc]
1778
1779    # Angle of the points
1780    theta = np.arctan2(ptB[0]-ptA[0],ptB[1]-ptA[1])
1781
1782    # rotating angle of the circ
1783    if pos == 'left': 
1784        rotangle = theta + np.pi/2. - alpha/2.
1785    elif pos == 'right':
1786        rotangle = theta + 3.*np.pi/2. - alpha/2.
1787    else:
1788        print errormsg
1789        print '  ' + fname + ": position '" + pos + "' not ready !!" 
1790        print '     available ones:', availpos
1791        quit(-1)
1792
1793    #print 'alpha:', alpha*180./np.pi, 'theta:', theta*180./np.pi, 'rotangle:', rotangle*180./np.pi
1794 
1795    # rotating the arc along the x-axis
1796    rotcirc_sec = rotate_polygon_2D(circ_sec, rotangle)
1797
1798    # Moving arc to the ptA
1799    circ_sec = rotcirc_sec + ptA
1800
1801    return circ_sec
1802
1803def p_square(face, N=5):
1804    """ Function to get a polygon square
1805      face: length of the face of the square
1806      N: number of points of the polygon
1807    """
1808    fname = 'p_square'
1809
1810    square = np.zeros((N,2), dtype=np.float)
1811
1812    f2 = face/2.
1813    N4 = N/4
1814    df = face/(N4)
1815    # SW-NW
1816    for ip in range(N4):
1817        square[ip,:] = [-f2+ip*df,-f2]
1818    # NW-NE
1819    for ip in range(N4):
1820        square[ip+N4,:] = [f2,-f2+ip*df]
1821    # NE-SE
1822    for ip in range(N4):
1823        square[ip+2*N4,:] = [f2-ip*df,f2]
1824    N42 = N-3*N4-1
1825    df = face/(N42)
1826    # SE-SW
1827    for ip in range(N42):
1828        square[ip+3*N4,:] = [-f2,f2-ip*df]
1829    square[N-1,:] = [-f2,-f2]
1830
1831    return square
1832
1833
1834def p_prism(base, height, N=5):
1835    """ Function to get a polygon prism
1836      base: length of the base of the prism
1837      height: length of the height of the prism
1838      N: number of points of the polygon
1839    """
1840    fname = 'p_prism'
1841
1842    prism = np.zeros((N,2), dtype=np.float)
1843
1844    b2 = base/2.
1845    h2 = height/2.
1846    N4 = N/4
1847    dh = height/(N4)
1848    db = base/(N4)
1849
1850    # SW-NW
1851    for ip in range(N4):
1852        prism[ip,:] = [-h2+ip*dh,-b2]
1853    # NW-NE
1854    for ip in range(N4):
1855        prism[ip+N4,:] = [h2,-b2+ip*db]
1856    # NE-SE
1857    for ip in range(N4):
1858        prism[ip+2*N4,:] = [h2-ip*dh,b2]
1859    N42 = N-3*N4-1
1860    db = base/(N42)
1861    # SE-SW
1862    for ip in range(N42):
1863        prism[ip+3*N4,:] = [-h2,b2-ip*db]
1864    prism[N-1,:] = [-h2,-b2]
1865
1866    return prism
1867
1868def p_circle(radii, N=50):
1869    """ Function to get a polygon of a circle
1870      radii: length of the radii of the circle
1871      N: number of points of the polygon
1872    """
1873    fname = 'p_circle'
1874
1875    circle = np.zeros((N,2), dtype=np.float)
1876
1877    dangle = 2.*np.pi/(N-1)
1878
1879    for ia in range(N):
1880        circle[ia,:] = [radii*np.sin(ia*dangle), radii*np.cos(ia*dangle)]
1881
1882    circle[N-1,:] = [0., radii]
1883
1884    return circle
1885
1886def p_triangle(p1, p2, p3, N=4):
1887    """ Function to provide the polygon of a triangle from its 3 vertices
1888      p1: vertex 1 [y,x]
1889      p2: vertex 2 [y,x]
1890      p3: vertex 3 [y,x]
1891      N: number of vertices of the triangle
1892    """
1893    fname = 'p_triangle'
1894
1895    triangle = np.zeros((N,2), dtype=np.float)
1896
1897    N3 = N / 3
1898    # 1-2
1899    dx = (p2[1]-p1[1])/N3
1900    dy = (p2[0]-p1[0])/N3
1901    for ip in range(N3):
1902        triangle[ip,:] = [p1[0]+ip*dy,p1[1]+ip*dx]
1903    # 2-3
1904    dx = (p3[1]-p2[1])/N3
1905    dy = (p3[0]-p2[0])/N3
1906    for ip in range(N3):
1907        triangle[ip+N3,:] = [p2[0]+ip*dy,p2[1]+ip*dx]
1908    # 3-1
1909    N32 = N - 2*N/3
1910    dx = (p1[1]-p3[1])/N32
1911    dy = (p1[0]-p3[0])/N32
1912    for ip in range(N32):
1913        triangle[ip+2*N3,:] = [p3[0]+ip*dy,p3[1]+ip*dx]
1914
1915    triangle[N-1,:] = p1
1916
1917    return triangle
1918
1919def p_spiral(loops, eradii, N=1000):
1920    """ Function to provide a polygon of an Archimedean spiral
1921        FROM: https://en.wikipedia.org/wiki/Spiral
1922      loops: number of loops of the spiral
1923      eradii: length of the radii of the final spiral
1924      N: number of points of the polygon
1925    """
1926    fname = 'p_spiral'
1927
1928    spiral = np.zeros((N,2), dtype=np.float)
1929
1930    dangle = 2.*np.pi*loops/(N-1)
1931    dr = eradii*1./(N-1)
1932
1933    for ia in range(N):
1934        radii = dr*ia
1935        spiral[ia,:] = [radii*np.sin(ia*dangle), radii*np.cos(ia*dangle)]
1936
1937    return spiral
1938
1939def p_reg_polygon(Nv, lf, N=50):
1940    """ Function to provide a regular polygon of Nv vertices
1941      Nv: number of vertices
1942      lf: length of the face
1943      N: number of points
1944    """
1945    fname = 'p_reg_polygon'
1946
1947    reg_polygon = np.zeros((N,2), dtype=np.float)
1948
1949    # Number of points per vertex
1950    Np = N/Nv
1951    # Angle incremental between vertices
1952    da = 2.*np.pi/Nv
1953    # Radii of the circle according to lf
1954    radii = lf*Nv/(2*np.pi)
1955
1956    iip = 0
1957    for iv in range(Nv-1):
1958        # Characteristics between vertices iv and iv+1
1959        av1 = da*iv
1960        v1 = [radii*np.sin(av1), radii*np.cos(av1)]
1961        av2 = da*(iv+1)
1962        v2 = [radii*np.sin(av2), radii*np.cos(av2)]
1963        dx = (v2[1]-v1[1])/Np
1964        dy = (v2[0]-v1[0])/Np
1965        for ip in range(Np):
1966            reg_polygon[ip+iv*Np,:] = [v1[0]+dy*ip,v1[1]+dx*ip]
1967
1968    # Characteristics between vertices Nv and 1
1969
1970    # Number of points per vertex
1971    Np2 = N - Np*(Nv-1)
1972
1973    av1 = da*Nv
1974    v1 = [radii*np.sin(av1), radii*np.cos(av1)]
1975    av2 = 0.
1976    v2 = [radii*np.sin(av2), radii*np.cos(av2)]
1977    dx = (v2[1]-v1[1])/Np2
1978    dy = (v2[0]-v1[0])/Np2
1979    for ip in range(Np2):
1980        reg_polygon[ip+(Nv-1)*Np,:] = [v1[0]+dy*ip,v1[1]+dx*ip]
1981
1982    return reg_polygon
1983
1984def p_reg_star(Nv, lf, freq, vs=0, N=50):
1985    """ Function to provide a regular star of Nv vertices
1986      Nv: number of vertices
1987      lf: length of the face of the regular polygon
1988      freq: frequency of union of vertices ('0', for just centered to zero arms)
1989      vs: vertex from which start (0 being first [0,lf])
1990      N: number of points
1991    """
1992    fname = 'p_reg_star'
1993
1994    reg_star = np.zeros((N,2), dtype=np.float)
1995
1996    # Number of arms of the star
1997    if freq != 0 and np.mod(Nv,freq) == 0: 
1998        Na = Nv/freq + 1
1999    else:
2000        Na = Nv
2001
2002    # Number of points per arm
2003    Np = N/Na
2004    # Angle incremental between vertices
2005    da = 2.*np.pi/Nv
2006    # Radii of the circle according to lf
2007    radii = lf*Nv/(2*np.pi)
2008
2009    iip = 0
2010    av1 = vs*da
2011    for iv in range(Na-1):
2012        # Characteristics between vertices iv and iv+1
2013        v1 = [radii*np.sin(av1), radii*np.cos(av1)]
2014        if freq != 0:
2015            av2 = av1 + da*freq
2016            v2 = [radii*np.sin(av2), radii*np.cos(av2)]
2017        else:
2018            v2 = [0., 0.]
2019            av2 = av1 + da
2020        dx = (v2[1]-v1[1])/(Np-1)
2021        dy = (v2[0]-v1[0])/(Np-1)
2022        for ip in range(Np):
2023            reg_star[ip+iv*Np,:] = [v1[0]+dy*ip,v1[1]+dx*ip]
2024        if av2 > 2.*np.pi: av1 = av2 - 2.*np.pi
2025        else: av1 = av2 + 0.
2026
2027    iv = Na-1
2028    # Characteristics between vertices Na and 1
2029    Np2 = N-Np*iv
2030    v1 = [radii*np.sin(av1), radii*np.cos(av1)]
2031    if freq != 0:
2032        av2 = vs*da
2033        v2 = [radii*np.sin(av2), radii*np.cos(av2)]
2034    else:
2035        v2 = [0., 0.]
2036    dx = (v2[1]-v1[1])/(Np2-1)
2037    dy = (v2[0]-v1[0])/(Np2-1)
2038    for ip in range(Np2):
2039        reg_star[ip+iv*Np,:] = [v1[0]+dy*ip,v1[1]+dx*ip]
2040
2041    return reg_star
2042
2043def p_sinusiode(length=10., amp=5., lamb=3., ival=0., func='sin', N=100):
2044    """ Function to get coordinates of a sinusoidal curve
2045      length: length of the line (default 10.)
2046      amp: amplitude of the peaks (default 5.)
2047      lamb: wave longitude (defalult 3.)
2048      ival: initial angle (default 0. in degree)
2049      func: function to use: (default sinus)
2050        'sin': sinus
2051        'cos': cosinus
2052      N: number of points (default 100)
2053    """
2054    fname = 'p_sinusiode'
2055    availfunc = ['sin', 'cos']
2056
2057    dx = length/(N-1)
2058    ia = ival*np.pi/180.
2059    da = 2*np.pi*dx/lamb
2060
2061    sinusoide = np.zeros((N,2), dtype=np.float)
2062    if func == 'sin':
2063        for ix in range(N):
2064            sinusoide[ix,:] = [amp*np.sin(ia+da*ix),dx*ix]
2065    elif func == 'cos':
2066        for ix in range(N):
2067            sinusoide[ix,:] = [amp*np.cos(ia+da*ix),dx*ix]
2068    else:
2069        print errormsg
2070        print '  ' + fname + ": function '" + func + "' not ready !!"
2071        print '    available ones:', availfunc
2072        quit(-1)
2073
2074    sinusoidesecs = ['sinusoide']
2075    sinusoidedic = {'sinusoide': [sinusoide, '-', '#000000', 1.]}
2076
2077    return sinusoide, sinusoidesecs, sinusoidedic
2078
2079def p_doubleArrow(length=5., angle=45., width=1., alength=0.10, N=50):
2080    """ Function to provide an arrow with double lines
2081      length: length of the arrow (5. default)
2082      angle: angle of the head of the arrow (45., default)
2083      width: separation between the two lines (2., default)
2084      alength: length of the head (as percentage in excess of width, 0.1 default)
2085      N: number of points (50, default)
2086    """
2087    function = 'p_doubleArrow'
2088
2089    doubleArrow = np.zeros((50,2), dtype=np.float)
2090    N4 = int((N-3)/4)
2091
2092    doublearrowdic = {}
2093    ddy = width*np.tan(angle*np.pi/180.)/2.
2094    # Arms
2095    dx = (length-ddy)/(N4-1)
2096    for ix in range(N4):
2097        doubleArrow[ix,:] = [dx*ix,-width/2.]
2098    doublearrowdic['leftarm'] = [doubleArrow[0:N4,:], '-', '#000000', 2.]
2099    doubleArrow[N4,:] = [gen.fillValueF,gen.fillValueF]
2100    for ix in range(N4):
2101        doubleArrow[N4+1+ix,:] = [dx*ix,width/2.]
2102    doublearrowdic['rightarm'] = [doubleArrow[N4+1:2*N4+1,:], '-', '#000000', 2.]
2103    doubleArrow[2*N4+1,:] = [gen.fillValueF,gen.fillValueF]
2104
2105    # Head
2106    N42 = int((N-2 - 2*N4)/2)
2107    dx = width*(1.+alength)*np.cos(angle*np.pi/180.)/(N42-1)
2108    dy = width*(1.+alength)*np.sin(angle*np.pi/180.)/(N42-1)
2109    for ix in range(N42):
2110        doubleArrow[2*N4+2+ix,:] = [length-dy*ix,-dx*ix]
2111    doublearrowdic['lefthead'] = [doubleArrow[2*N4:2*N4+N42,:], '-', '#000000', 2.]
2112    doubleArrow[2*N4+2+N42,:] = [gen.fillValueF,gen.fillValueF]
2113
2114    N43 = N-3 - 2*N4 - N42 + 1
2115    dx = width*(1.+alength)*np.cos(angle*np.pi/180.)/(N43-1)
2116    dy = width*(1.+alength)*np.sin(angle*np.pi/180.)/(N43-1)
2117    for ix in range(N43):
2118        doubleArrow[2*N4+N42+2+ix,:] = [length-dy*ix,dx*ix]
2119    doublearrowdic['rightthead'] = [doubleArrow[2*N4+N42+2:51,:], '-', '#000000', 2.]
2120
2121    doubleArrow = ma.masked_equal(doubleArrow, gen.fillValueF)
2122    doublearrowsecs = ['leftarm', 'rightarm', 'lefthead', 'righthead']
2123
2124    return doubleArrow, doublearrowsecs, doublearrowdic
2125
2126def p_angle_triangle(pi=np.array([0.,0.]), angle1=60., length1=1., angle2=60., N=100):
2127    """ Function to draw a triangle by an initial point and two consecutive angles
2128        and the first length of face. The third angle and 2 and 3rd face will be
2129        computed accordingly the provided values:
2130           length1 / sin(angle1) = length2 / sin(angle2) = length3 / sin(angle3)
2131           angle1 + angle2 + angle3 = 180.
2132      pi: initial point ([0., 0.], default)
2133      angle1: first angle from pi clockwise (60., default)
2134      length1: length of face from pi by angle1 (1., default)
2135      angle2: second angle from second point (60., default)
2136      length2: length of face from p2 by angle2 (1., default)
2137      N: number of points (100, default)
2138    """
2139    fname = 'p_angle_triangle'
2140
2141    angle3 = 180. - angle1 - angle2
2142    length2 = np.sin(angle2*np.pi/180.)*length1/np.sin(angle1*np.pi/180.)
2143    length3 = np.sin(angle3*np.pi/180.)*length1/np.sin(angle1*np.pi/180.)
2144
2145    triangle = np.zeros((N,2), dtype=np.float)
2146
2147    N3 = int(N/3)
2148    # first face
2149    ix = pi[1]
2150    iy = pi[0]
2151    dx = length1*np.cos(angle1*np.pi/180.)/(N3-1)
2152    dy = length1*np.sin(angle1*np.pi/180.)/(N3-1)
2153    for ip in range(N3):
2154        triangle[ip,:] = [iy+dy*ip, ix+dx*ip]
2155
2156    # second face
2157    ia = -90. - (90.-angle1)
2158    ix = triangle[N3-1,1]
2159    iy = triangle[N3-1,0]
2160    dx = length2*np.cos((ia+angle2)*np.pi/180.)/(N3-1)
2161    dy = length2*np.sin((ia+angle2)*np.pi/180.)/(N3-1)
2162    for ip in range(N3):
2163        triangle[N3+ip,:] = [iy+dy*ip, ix+dx*ip]
2164
2165    # third face
2166    N32 = N - 2*N3
2167    ia = -180. - (90.-angle2)
2168    ix = triangle[2*N3-1,1]
2169    iy = triangle[2*N3-1,0]
2170    angle3 = np.arctan2(pi[0]-iy, pi[1]-ix)
2171    dx = (pi[1]-ix)/(N32-1)
2172    dy = (pi[0]-iy)/(N32-1)
2173    for ip in range(N32):
2174        triangle[2*N3+ip,:] = [iy+dy*ip, ix+dx*ip]
2175
2176    return triangle
2177
2178def p_cross_width(larm=5., width=1., Narms=4, N=200):
2179    """ Function to draw a cross with arms with a given width and an angle
2180      larm: legnth of the arms (5., default)
2181      width: width of the arms (1., default)
2182      Narms: Number of arms (4, default)
2183      N: number of points to us (200, default)
2184    """
2185    fname = 'p_cross_width'
2186
2187    Narm = int((N-Narms)/Narms)
2188
2189    larm2 = larm/2.
2190    width2 = width/2.
2191
2192    cross = np.ones((N,2), dtype=np.float)*gen.fillValueF
2193    da = np.pi/Narms
2194
2195    N1 = int(Narm*3./8.)
2196    N2 = int((Narm - 2*N1)/2.)
2197    N21 = Narm - 2*N1 - N2
2198
2199    if N2 < 3:
2200        print errormsg
2201        print '  ' + fname + ": too few points for ", Narms, " arms !!"
2202        print "    increase number 'N' at least up to '", 25*Narms
2203        quit(-1)
2204
2205    crosssecs = []
2206    crossdic = {}
2207    Npot = int(np.log10(Narms))+1
2208
2209    iip = 0
2210    for iarm in range(Narms-1):
2211
2212        a = da*iarm
2213        iip0 = iip
2214
2215        # bottom coordinate
2216        bx = larm*np.cos(a+np.pi)
2217        by = larm*np.sin(a+np.pi)
2218
2219        # upper coordinate
2220        ux = larm*np.cos(a)
2221        uy = larm*np.sin(a)
2222
2223        rela = a+np.pi*3./2.
2224        # SW-NW
2225        ix = bx + width2*np.cos(rela)
2226        iy = by + width2*np.sin(rela)
2227        ex = ux + width2*np.cos(rela)
2228        ey = uy + width2*np.sin(rela)
2229        dx = (ex-ix)/(N1-1)
2230        dy = (ey-iy)/(N1-1)
2231        for ip in range(N1):
2232            cross[iip+ip,:] = [iy+dy*ip,ix+dx*ip]
2233        iip = iip + N1
2234
2235        # NW-NE
2236        ix = ex + 0.
2237        iy = ey + 0.
2238        ex = ux - width2*np.cos(rela)
2239        ey = uy - width2*np.sin(rela)
2240        dx = (ex-ix)/(N2-1)
2241        dy = (ey-iy)/(N2-1)
2242        for ip in range(N2):
2243            cross[iip+ip,:] = [iy+dy*ip,ix+dx*ip]
2244        iip = iip + N2
2245
2246        # NW-SW
2247        ix = ex + 0.
2248        iy = ey + 0.
2249        ex = bx - width2*np.cos(rela)
2250        ey = by - width2*np.sin(rela)
2251        dx = (ex-ix)/(N1-1)
2252        dy = (ey-iy)/(N1-1)
2253        for ip in range(N1):
2254            cross[iip+ip,:] = [iy+dy*ip,ix+dx*ip]
2255        iip = iip + N1
2256
2257        # SW-SE
2258        ix = ex + 0.
2259        iy = ey + 0.
2260        ex = bx + width2*np.cos(rela)
2261        ey = by + width2*np.sin(rela)
2262        dx = (ex-ix)/(N21-1)
2263        dy = (ey-iy)/(N21-1)
2264        for ip in range(N21):
2265            cross[iip+ip,:] = [iy+dy*ip,ix+dx*ip]
2266        iip = iip + N21 + 1
2267
2268        iarmS = str(iarm).zfill(Npot)
2269        crosssecs.append(iarmS)
2270        crossdic[iarmS] = [cross[iip0:iip0+iip-1], '-', 'k', '1.']
2271
2272    iip0 = iip
2273
2274    Narm = N - Narm*(Narms-1) - Narms
2275
2276    N1 = int(Narm*3./8.)
2277    N2 = int((Narm - 2*N1)/2.)
2278    N21 = Narm - 2*N1 - N2
2279
2280    iarm = Narms-1
2281    a = da*iarm
2282
2283    # bottom coordinate
2284    bx = larm*np.cos(a+np.pi)
2285    by = larm*np.sin(a+np.pi)
2286
2287    # upper coordinate
2288    ux = larm*np.cos(a)
2289    uy = larm*np.sin(a)
2290
2291    rela = a+np.pi*3./2.
2292    # SW-NW
2293    ix = bx + width2*np.cos(rela)
2294    iy = by + width2*np.sin(rela)
2295    ex = ux + width2*np.cos(rela)
2296    ey = uy + width2*np.sin(rela)
2297    dx = (ex-ix)/(N1-1)
2298    dy = (ey-iy)/(N1-1)
2299    for ip in range(N1):
2300      cross[iip+ip,:] = [iy+dy*ip,ix+dx*ip]
2301    iip = iip + N1
2302
2303    # NW-NE
2304    ix = ex + 0.
2305    iy = ey + 0.
2306    ex = ux - width2*np.cos(rela)
2307    ey = uy - width2*np.sin(rela)
2308    dx = (ex-ix)/(N2-1)
2309    dy = (ey-iy)/(N2-1)
2310    for ip in range(N2):
2311      cross[iip+ip,:] = [iy+dy*ip,ix+dx*ip]
2312    iip = iip + N2
2313
2314    # NW-SW
2315    ix = ex + 0.
2316    iy = ey + 0.
2317    ex = bx - width2*np.cos(rela)
2318    ey = by - width2*np.sin(rela)
2319    dx = (ex-ix)/(N1-1)
2320    dy = (ey-iy)/(N1-1)
2321    for ip in range(N1):
2322      cross[iip+ip,:] = [iy+dy*ip,ix+dx*ip]
2323    iip = iip + N1
2324
2325    # SW-SE
2326    ix = ex + 0.
2327    iy = ey + 0.
2328    ex = bx + width2*np.cos(rela)
2329    ey = by + width2*np.sin(rela)
2330    dx = (ex-ix)/(N21-1)
2331    dy = (ey-iy)/(N21-1)
2332    for ip in range(N21):
2333      cross[iip+ip,:] = [iy+dy*ip,ix+dx*ip]
2334    iip = iip + N21
2335
2336    iarmS = str(iarm).zfill(Npot)
2337    crosssecs.append(iarmS)
2338    crossdic[iarmS] = [cross[iip0:iip0+iip-1], '-', 'k', '1.']
2339
2340    cross = ma.masked_equal(cross, gen.fillValueF)
2341
2342    return cross, crosssecs, crossdic
2343
2344# Combined objects
2345##
2346
2347# FROM: http://www.photographers1.com/Sailing/NauticalTerms&Nomenclature.html
2348def zboat(length=10., beam=1., lbeam=0.4, sternbp=0.5):
2349    """ Function to define an schematic boat from the z-plane
2350      length: length of the boat (without stern, default 10)
2351      beam: beam of the boat (default 1)
2352      lbeam: length at beam (as percentage of length, default 0.4)
2353      sternbp: beam at stern (as percentage of beam, default 0.5)
2354    """
2355    fname = 'zboat'
2356
2357    bow = np.array([length, 0.])
2358    maxportside = np.array([length*lbeam, -beam])
2359    maxstarboardside = np.array([length*lbeam, beam])
2360    portside = np.array([0., -beam*sternbp])
2361    starboardside = np.array([0., beam*sternbp])
2362
2363    # forward section
2364    fportside = circ_sec(maxportside, bow, length*2)
2365    fstarboardside = circ_sec(bow, maxstarboardside, length*2)
2366    # aft section
2367    aportside = circ_sec(portside, maxportside, length*2)
2368    astarboardside = circ_sec(maxstarboardside, starboardside, length*2)
2369    # stern
2370    stern = circ_sec(starboardside, portside, length*2)
2371
2372    dpts = stern.shape[0]
2373    boat = np.zeros((dpts*5,2), dtype=np.float)
2374
2375    boat[0:dpts,:] = aportside
2376    boat[dpts:2*dpts,:] = fportside
2377    boat[2*dpts:3*dpts,:] = fstarboardside
2378    boat[3*dpts:4*dpts,:] = astarboardside
2379    boat[4*dpts:5*dpts,:] = stern
2380
2381    fname = 'boat_L' + str(int(length*100.)) + '_B' + str(int(beam*100.)) + '_lb' +  \
2382      str(int(lbeam*100.)) + '_sb' + str(int(sternbp*100.)) + '.dat'
2383    if not os.path.isfile(fname):
2384        print infmsg
2385        print '  ' + fname + ": writting boat coordinates file '" + fname + "' !!"
2386        of = open(fname, 'w')
2387        of.write('# boat file with Length: ' + str(length) +' max_beam: '+str(beam)+ \
2388          'length_at_max_beam:' + str(lbeam) + '% beam at stern: ' + str(sternbp)+   \
2389          ' %\n')
2390        for ip in range(dpts*5):
2391            of.write(str(boat[ip,0]) + ' ' + str(boat[ip,1]) + '\n')
2392       
2393        of.close()
2394        print fname + ": Successfull written '" + fname + "' !!"
2395
2396
2397    # Center line extending [fcl] percentage from length on aft and stern
2398    fcl = 0.15
2399    centerline = np.zeros((dpts,2), dtype=np.float)
2400    dl = length*(1.+fcl*2.)/(dpts-1)
2401    centerline[:,0] = np.arange(-length*fcl, length*(1. + fcl)+dl, dl)
2402
2403    # correct order of sections
2404    boatsecs = ['aportside', 'fportside', 'fstarboardside', 'astarboardside',        \
2405      'stern', 'centerline']
2406
2407    # dictionary with sections [polygon_vertices, line_type, line_color, line_width]
2408    dicboat = {'fportside': [fportside, '-', '#8A5900', 2.],                         \
2409      'aportside': [aportside, '-', '#8A5900', 2.],                                  \
2410      'stern': [stern, '-', '#8A5900', 2.],                                          \
2411      'astarboardside': [astarboardside, '-', '#8A5900', 2.],                        \
2412      'fstarboardside': [fstarboardside, '-', '#8A5900', 2.],                        \
2413      'centerline': [centerline, '-.', '#AA6464', 1.5]}
2414   
2415    fname = 'sailboat_L' + str(int(length*100.)) + '_B' + str(int(beam*100.)) +      \
2416      '_lb' + str(int(lbeam*100.)) + '_sb' + str(int(sternbp*100.)) +'.dat'
2417    if not os.path.isfile(fname):
2418        print infmsg
2419        print '  ' + fname + ": writting boat coordinates file '" + fname + "' !!"
2420        of = open(fname, 'w')
2421        of.write('# boat file with Length: ' + str(length) +' max_beam: '+str(beam)+ \
2422          'length_at_max_beam:' + str(lbeam) + '% beam at stern: ' +str(sternbp)+'\n')
2423        for ip in range(dpts*5):
2424            of.write(str(boat[ip,0]) + ' ' + str(boat[ip,1]) + '\n')
2425       
2426        of.close()
2427        print fname + ": Successfull written '" + fname + "' !!"
2428 
2429    return boat, boatsecs, dicboat
2430
2431def zsailing_boat(length=10., beam=1., lbeam=0.4, sternbp=0.5, lmast=0.6, wmast=0.1, \
2432  hsd=5., msd=5., lheads=0.38, lmains=0.55):
2433    """ Function to define an schematic sailing boat from the z-plane with sails
2434      length: length of the boat (without stern, default 10)
2435      beam: beam of the boat (default 1)
2436      lbeam: length at beam (as percentage of length, default 0.4)
2437      sternbp: beam at stern (as percentage of beam, default 0.5)
2438      lmast: position of the mast (as percentage of length, default 0.6)
2439      wmast: width of the mast (default 0.1)
2440      hsd: head sail direction respect to center line (default 5., -999.99 for upwind)
2441      msd: main sail direction respect to center line (default 5., -999.99 for upwind)
2442      lheads: length of head sail (as percentage of legnth, defaul 0.38)
2443      lmains: length of main sail (as percentage of legnth, defaul 0.55)
2444    """
2445    fname = 'zsailing_boat'
2446
2447    bow = np.array([length, 0.])
2448    maxportside = np.array([length*lbeam, -beam])
2449    maxstarboardside = np.array([length*lbeam, beam])
2450    portside = np.array([0., -beam*sternbp])
2451    starboardside = np.array([0., beam*sternbp])
2452
2453    aportside = circ_sec(portside, maxportside, length*2)
2454    fportside = circ_sec(maxportside, bow, length*2)
2455    fstarboardside = circ_sec(bow, maxstarboardside, length*2)
2456    astarboardside = circ_sec(maxstarboardside, starboardside, length*2)
2457    stern = circ_sec(starboardside, portside, length*2)
2458    dpts = fportside.shape[0]
2459
2460    # correct order of sections
2461    sailingboatsecs = ['aportside', 'fportside', 'fstarboardside', 'astarboardside', \
2462      'stern', 'mast', 'hsail', 'msail', 'centerline']
2463
2464    # forward section
2465
2466    # aft section
2467    # stern
2468    # mast
2469    mast = p_circle(wmast,N=dpts)
2470    mast = mast + [length*lmast, 0.]
2471    # head sails
2472    lsail = lheads*length
2473    if hsd != -999.99:
2474        sailsa = np.pi/2. - np.pi*hsd/180.
2475        endsail = np.array([lsail*np.sin(sailsa), lsail*np.cos(sailsa)])
2476        endsail[0] = length - endsail[0]
2477        if bow[1] > endsail[1]:
2478            hsail = circ_sec(endsail, bow, lsail*2.15)
2479        else:
2480            hsail = circ_sec(bow, endsail, lsail*2.15)
2481    else:
2482        hsail0 = p_sinusiode(length=lsail, amp=0.2, lamb=0.75, N=dpts)
2483        hsail = np.zeros((dpts,2), dtype=np.float)
2484        hsail[:,0] = hsail0[:,1]
2485        hsail[:,1] = hsail0[:,0]
2486        hsail = bow - hsail
2487
2488    # main sails
2489    lsail = lmains*length
2490    if msd != -999.99:
2491        sailsa = np.pi/2. - np.pi*msd/180.
2492        begsail = np.array([length*lmast, 0.])
2493        endsail = np.array([lsail*np.sin(sailsa), lsail*np.cos(sailsa)])
2494        endsail[0] = length*lmast - endsail[0]
2495        if endsail[1] > begsail[1]:
2496            msail = circ_sec(begsail, endsail, lsail*2.15)
2497        else:
2498            msail = circ_sec(endsail, begsail, lsail*2.15)
2499    else:
2500        msail0 = p_sinusiode(length=lsail, amp=0.25, lamb=1., N=dpts)
2501        msail = np.zeros((dpts,2), dtype=np.float)
2502        msail[:,0] = msail0[:,1]
2503        msail[:,1] = msail0[:,0]
2504        msail = [length*lmast,0] - msail
2505
2506    sailingboat = np.zeros((dpts*8+4,2), dtype=np.float)
2507
2508    sailingboat[0:dpts,:] = aportside
2509    sailingboat[dpts:2*dpts,:] = fportside
2510    sailingboat[2*dpts:3*dpts,:] = fstarboardside
2511    sailingboat[3*dpts:4*dpts,:] = astarboardside
2512    sailingboat[4*dpts:5*dpts,:] = stern
2513    sailingboat[5*dpts,:] = [gen.fillValueF, gen.fillValueF]
2514    sailingboat[5*dpts+1:6*dpts+1,:] = mast
2515    sailingboat[6*dpts+1,:] = [gen.fillValueF, gen.fillValueF]
2516    sailingboat[6*dpts+2:7*dpts+2,:] = hsail
2517    sailingboat[7*dpts+2,:] = [gen.fillValueF, gen.fillValueF]
2518    sailingboat[7*dpts+3:8*dpts+3,:] = msail
2519    sailingboat[8*dpts+3,:] = [gen.fillValueF, gen.fillValueF]
2520
2521    sailingboat = ma.masked_equal(sailingboat, gen.fillValueF)
2522
2523    # Center line extending [fcl] percentage from length on aft and stern
2524    fcl = 0.15
2525    centerline = np.zeros((dpts,2), dtype=np.float)
2526    dl = length*(1.+fcl*2.)/(dpts-1)
2527    centerline[:,0] = np.arange(-length*fcl, length*(1. + fcl)+dl, dl)
2528
2529    # dictionary with sections [polygon_vertices, line_type, line_color, line_width]
2530    dicsailingboat = {'fportside': [fportside, '-', '#8A5900', 2.],                  \
2531      'aportside': [aportside, '-', '#8A5900', 2.],                                  \
2532      'stern': [stern, '-', '#8A5900', 2.],                                          \
2533      'astarboardside': [astarboardside, '-', '#8A5900', 2.],                        \
2534      'fstarboardside': [fstarboardside, '-', '#8A5900', 2.],                        \
2535      'mast': [mast, '-', '#8A5900', 2.], 'hsail': [hsail, '-', '#AAAAAA', 1.],      \
2536      'msail': [msail, '-', '#AAAAAA', 1.],                                          \
2537      'centerline': [centerline, '-.', '#AA6464', 1.5]}
2538   
2539    fname = 'sailboat_L' + str(int(length*100.)) + '_B' + str(int(beam*100.)) +      \
2540      '_lb' + str(int(lbeam*100.)) + '_sb' + str(int(sternbp*100.)) +                \
2541      '_lm' + str(int(lmast*100.)) + '_wm' + str(int(wmast)) +                       \
2542      '_hsd' + str(int(hsd)) + '_hs' + str(int(lheads*100.)) +                       \
2543      '_ms' + str(int(lheads*100.)) + '_msd' + str(int(msd)) +'.dat'
2544    if not os.path.isfile(fname):
2545        print infmsg
2546        print '  ' + fname + ": writting boat coordinates file '" + fname + "' !!"
2547        of = open(fname, 'w')
2548        of.write('# boat file with Length: ' + str(length) +' max_beam: '+str(beam)+ \
2549          'length_at_max_beam:' + str(lbeam) + '% beam at stern: ' + str(sternbp)+   \
2550          ' % mast position: '+ str(lmast) + ' % mast width: ' + str(wmast) + ' ' +  \
2551          ' head sail direction:' + str(hsd) + ' head sail length: ' + str(lheads) + \
2552          ' %' + ' main sail length' + str(lmains) + ' main sail direction:' +       \
2553          str(msd) +'\n')
2554        for ip in range(dpts*5):
2555            of.write(str(sailingboat[ip,0]) + ' ' + str(sailingboat[ip,1]) + '\n')
2556       
2557        of.close()
2558        print fname + ": Successfull written '" + fname + "' !!"
2559 
2560    return sailingboat, sailingboatsecs, dicsailingboat
2561
2562def zisland1(mainpts= np.array([[-0.1,0.], [-1.,1.], [-0.8,1.2], [0.1,0.6], [1., 0.9],\
2563  [2.8, -0.1], [0.1,-0.6]], dtype=np.float), radfrac=3., N=200):
2564    """ Function to draw an island from z-axis as the union of a series of points by
2565        circular segments
2566      mainpts: main points of the island (clockwise ordered, to be joined by
2567        circular segments of radii as the radfrac factor of the distance between
2568        consecutive points)
2569          * default= np.array([[-0.1,0.], [-1.,1.], [-0.8,1.2], [0.1,0.6], [1., 0.9],
2570            [2.8, -0.1], [0.1,-0.6]], dtype=np.float)
2571      radfrac: multiplicative factor of the distance between consecutive points to
2572        draw the circular segment (3., default)
2573      N: number of points (200, default)
2574    """
2575    fname = 'zisland1'
2576
2577    island1 = np.ones((N,2), dtype=np.float)*gen.fillValueF
2578
2579    # Coastline
2580    island1 = join_circ_sec_rand(mainpts, arc='short', pos='left')
2581
2582    islandsecs = ['coastline']
2583    islanddic = {'coastline': [island1, '-', '#161616', 2.]}
2584
2585    island1 = ma.masked_equal(island1, gen.fillValueF)
2586
2587    return island1, islandsecs, islanddic
2588
2589def buoy1(height=5., width=10., bradii=1.75, bfrac=0.8, N=300):
2590    """ Function to draw a buoy as superposition of prism and section of ball
2591      height: height of the prism (5., default)
2592      width: width of the prism (10., default)
2593      bradii: radii of the ball (1.75, default)
2594      bfrac: fraction of the ball above the prism (0.8, default)
2595      N: total number of points of the buoy (300, default)
2596    """
2597    fname = 'buoy1'
2598
2599    buoy = np.zeros((N,2), dtype=np.float)
2600
2601    N3 = int(N/3/5)
2602    NNp = 0
2603    iip = 0
2604    # left lateral
2605    ix = -width/2.
2606    Np = N3
2607    iy = 0.
2608    dx = 0.
2609    dy = height/(Np)
2610    for ip in range(Np):
2611        buoy[iip+ip,:] = [iy+dy*ip,ix+dx*ip]
2612    NNp = NNp + Np
2613    iip = NNp
2614
2615    # left upper
2616    ix = -width/2.
2617    iy = height
2618    dx = (width/2.-bradii*bfrac)/(Np)
2619    dy = 0.
2620    for ip in range(Np):
2621        buoy[iip+ip,:] = [iy+dy*ip,ix+dx*ip]
2622    NNp = NNp + Np
2623    iip = NNp
2624
2625    # ball
2626    p1 = np.array([height, -bradii*bfrac])
2627    p2 = np.array([height, bradii*bfrac])
2628    Np = int(2*N/3)
2629    buoy[iip:iip+Np,:] = circ_sec(p1, p2, 2.*bradii, 'long', 'left', Np)
2630    NNp = NNp + Np
2631    iip = NNp
2632
2633    # right upper
2634    ix = bradii*bfrac
2635    iy = height
2636    Np = N3
2637    dx = (width/2.-bradii*bfrac)/(Np)
2638    dy = 0.
2639    for ip in range(Np):
2640        buoy[iip+ip,:] = [iy+dy*ip,ix+dx*ip]
2641    NNp = NNp + Np
2642    iip = NNp
2643
2644    # right lateral
2645    ix = width/2.
2646    iy = height
2647    dx = 0.
2648    dy = -height/(Np)
2649    for ip in range(Np):
2650        buoy[iip+ip,:] = [iy+dy*ip,ix+dx*ip]
2651    NNp = NNp + Np
2652    iip = NNp
2653
2654    # Base
2655    ix = width/2.
2656    iy = 0.
2657    Np = N - int(2*N/3) - 4*N3 - 1
2658    dx = -width/(Np)
2659    dy = 0.
2660    for ip in range(Np):
2661        buoy[iip+ip,:] = [iy+dy*ip,ix+dx*ip]
2662    NNp = NNp + Np
2663    iip = NNp
2664
2665    buoy[N-1,:] = buoy[0,:]
2666
2667    buoysecs = ['base']
2668    buoydic = {'base': [buoy, '-', 'k', 1.5]}
2669
2670    return buoy, buoysecs, buoydic
2671
2672def band_lighthouse(height=10., width=2., hlight=3., bands=3, N=300):
2673    """ Function to plot a lighthouse with spiral bands
2674      height: height of the tower (10., default)
2675      width: width of the tower (2., default)
2676      hlight: height of the light (3., default)
2677      bands: number of spiral bands (3, default)
2678      N: number of points (300, default)
2679    """
2680    fname = 'band_lighthouse'
2681
2682    lighthouse = np.ones((N,2), dtype=np.float)*gen.fillValueF
2683    lighthousesecs = []
2684    lighthousedic = {}
2685
2686    # base Tower
2687    Nsec = int(0.30*N/7)
2688    p1=np.array([0., width/2.])
2689    p2=np.array([0., -width/2.])
2690    iip = 0
2691    lighthouse[0:Nsec,:] = circ_sec(p1, p2, 3*width, pos='left', Nang=Nsec)
2692    iip = iip + Nsec
2693
2694    # left side
2695    ix=-width/2.
2696    iy=0.
2697    dx = 0.
2698    dy = height/(Nsec-1)
2699    for ip in range(Nsec):
2700        lighthouse[iip+ip,:] = [iy+dy*ip, ix+dx*ip]
2701    iip = iip + Nsec
2702
2703    # Top Tower
2704    p1=np.array([height, width/2.])
2705    p2=np.array([height, -width/2.])
2706    lighthouse[iip:iip+Nsec,:] = circ_sec(p1, p2, 3*width, pos='left', Nang=Nsec)
2707    iip = iip + Nsec
2708
2709    # right side
2710    ix=width/2.
2711    iy=height
2712    dx = 0.
2713    dy = -height/(Nsec-1)
2714    for ip in range(Nsec):
2715        lighthouse[iip+ip,:] = [iy+dy*ip, ix+dx*ip]
2716    iip = iip + Nsec + 1
2717
2718    Ntower = iip-1
2719    lighthousesecs.append('tower')
2720    lighthousedic['tower'] = [lighthouse[0:iip-1], '-', 'k', 1.5]
2721
2722    # Left light
2723    p1 = np.array([height, -width*0.8/2.])
2724    p2 = np.array([height+hlight, -width*0.8/2.])
2725    lighthouse[iip:iip+Nsec,:] = circ_sec(p1, p2, 3*hlight, Nang=Nsec)
2726    iip = iip + Nsec
2727   
2728    # Top Light
2729    p1=np.array([height+hlight, width*0.8/2.])
2730    p2=np.array([height+hlight, -width*0.8/2.])
2731    lighthouse[iip:iip+Nsec,:] = circ_sec(p1, p2, 3*width, pos='left', Nang=Nsec)
2732    iip = iip + Nsec + 1
2733
2734    # Right light
2735    p1 = np.array([height+hlight, width*0.8/2.])
2736    p2 = np.array([height, width*0.8/2.])
2737    lighthouse[iip:iip+Nsec,:] = circ_sec(p1, p2, 3*hlight, Nang=Nsec)
2738    iip = iip + Nsec
2739
2740    # Base Light
2741    p1=np.array([height, width*0.8/2.])
2742    p2=np.array([height, -width*0.8/2.])
2743    lighthouse[iip:iip+Nsec,:] = circ_sec(p1, p2, 3*width, pos='left', Nang=Nsec)
2744    iip = iip + Nsec + 1
2745    lighthousesecs.append('light')
2746    lighthousedic['light'] = [lighthouse[Ntower+1:iip-1], '-', '#EEEE00', 1.5]
2747
2748    # Spiral bands
2749    hb = height/(2.*bands)
2750    Nsec2 = (N - Nsec*8 - 3)/bands
2751    for ib in range(bands-1):
2752        iband = iip
2753        Nsec = Nsec2/4
2754        bandS = 'band' + str(ib).zfill(2)
2755        # hband
2756        ix = -width/2.
2757        iy = hb*ib*2
2758        dx = 0.
2759        dy = hb/(Nsec-1)
2760        for ip in range(Nsec):
2761            lighthouse[iip+ip,:] = [iy+dy*ip, ix+dx*ip]
2762        iip = iip + Nsec
2763        # uband
2764        p1 = np.array([hb*(ib*2+1), -width/2.])
2765        p2 = np.array([hb*(ib*2+2), width/2.])
2766        lighthouse[iip:iip+Nsec,:] = circ_sec(p1, p2, 3*width, pos='right', Nang=Nsec)
2767        iip = iip + Nsec
2768        # dband
2769        ix = width/2.
2770        iy = hb*(ib*2+2)
2771        dx = 0.
2772        dy = -hb/(Nsec-1)
2773        for ip in range(Nsec):
2774            lighthouse[iip+ip,:] = [iy+dy*ip, ix+dx*ip]
2775        iip = iip + Nsec
2776        # dband
2777        p1 = np.array([hb*(ib*2+1), width/2.])
2778        p2 = np.array([hb*ib*2, -width/2.])
2779        lighthouse[iip:iip+Nsec,:] = circ_sec(p1, p2, 3*width, pos='left', Nang=Nsec)
2780        iip = iip + Nsec + 1
2781        lighthousesecs.append(bandS)
2782        lighthousedic[bandS] = [lighthouse[iband:iip-1], '-', '#6408AA', 2.]
2783
2784    ib = bands-1
2785    Nsec3 = (N - iip - 1)
2786    Nsec = int(Nsec3/4)
2787    bandS = 'band' + str(ib).zfill(2)
2788    # hband
2789    iband = iip
2790    ix = -width/2.
2791    iy = hb*ib*2
2792    dx = 0.
2793    dy = hb/(Nsec-1)
2794    for ip in range(Nsec):
2795        lighthouse[iip+ip,:] = [iy+dy*ip, ix+dx*ip]
2796    iip = iip + Nsec
2797    # uband
2798    p1 = np.array([hb*(ib*2+1), -width/2.])
2799    p2 = np.array([hb*(ib*2+2), width/2.])
2800    lighthouse[iip:iip+Nsec,:] = circ_sec(p1, p2, 3*width, pos='right', Nang=Nsec)
2801    iip = iip + Nsec
2802    # dband
2803    ix = width/2.
2804    iy = hb*(2+ib*2)
2805    dx = 0.
2806    dy = -hb/(Nsec-1)
2807    for ip in range(Nsec):
2808        lighthouse[iip+ip,:] = [iy+dy*ip, ix+dx*ip]
2809    iip = iip + Nsec
2810    # dband
2811    Nsec = N - iip
2812    p1 = np.array([hb*(1+ib*2), width/2.])
2813    p2 = np.array([hb*ib*2, -width/2.])
2814    lighthouse[iip:iip+Nsec,:] = circ_sec(p1, p2, 3*width, pos='left', Nang=Nsec)       
2815    lighthousesecs.append(bandS)
2816    lighthousedic[bandS] = [lighthouse[iband:iip-1], '-', '#6408AA', 2.]
2817
2818    lighthouse = ma.masked_equal(lighthouse, gen.fillValueF)
2819
2820    return lighthouse, lighthousesecs, lighthousedic
2821
2822def north_buoy1(height=5., width=10., bradii=1.75, bfrac=0.8, hsigns=0.7, N=300):
2823    """ Function to draw a North danger buoy using buoy1
2824      height: height of the prism (5., default)
2825      width: width of the prism (10., default)
2826      bradii: radii of the ball (1.75, default)
2827      bfrac: fraction of the ball above the prism (0.8, default)
2828      hisgns: height of the signs [as reg. triangle] as percentage of the height
2829        (0.7, default)
2830      N: total number of points of the buoy (300, default)
2831    """
2832    fname = 'north_buoy1'
2833
2834    buoy = np.ones((N,2), dtype=np.float)*gen.fillValueF
2835
2836    # buoy
2837    N2 = int(N/2)
2838    buoy1v, buoy1vsecs, buoy1vdic = buoy1(height=5., width=10., bradii=1.75,         \
2839      bfrac=0.8, N=N2)
2840    buoy[0:N2,:] = buoy1v
2841
2842    # signs
2843    N3 = N - N2 - 2
2844   
2845    bottsigns = 2.*bradii+height
2846    lsign = height*hsigns
2847    # up
2848    N32 = int(N3/2) 
2849    triu = p_angle_triangle(N=N32)
2850    trib = triu*lsign + [0.,-lsign/2.] 
2851
2852    buoy[N2+1:N2+1+N32,:] = trib + [bottsigns+2.1*lsign,0.]
2853
2854    # up
2855    N323 = N - N32 - N2 - 2
2856    trid = p_angle_triangle(N=N323)
2857    trib = trid*lsign + [0.,-lsign/2.] 
2858    buoy[N2+N32+2:N,:] = trib + [bottsigns+1.1*lsign,0.]
2859
2860    # painting it
2861    Height = np.max(buoy1v[:,0])
2862
2863    Ncut, halfdown = cut_ypolygon(buoy1v, yval=Height/2., keep='below')
2864    Ncut, halfup = cut_ypolygon(buoy1v, yval=Height/2., keep='above')
2865
2866    buoy = ma.masked_equal(buoy, gen.fillValueF)
2867
2868    buoysecs = ['buoy', 'sign1', 'sign2', 'half1', 'half2']
2869    buoydic = {'buoy': [buoy[0:N2,:],'-','k',1.5],                                   \
2870      'sign1': [buoy[N2+1:N2+N32+1,:],'-','k',1.5],                                  \
2871      'sign2': [buoy[N2+N32+2:N,:],'-','k',1.5], 'half1': [halfup, '-', 'k', 1.],    \
2872      'half2': [halfdown, '-', '#FFFF00', 1.]}
2873
2874    return buoy, buoysecs, buoydic
2875
2876def east_buoy1(height=5., width=10., bradii=1.75, bfrac=0.8, hsigns=0.7, N=300):
2877    """ Function to draw a East danger buoy using buoy1
2878      height: height of the prism (5., default)
2879      width: width of the prism (10., default)
2880      bradii: radii of the ball (1.75, default)
2881      bfrac: fraction of the ball above the prism (0.8, default)
2882      hisgns: height of the signs [as reg. triangle] as percentage of the height
2883        (0.7, default)
2884      N: total number of points of the buoy (300, default)
2885    """
2886    fname = 'east_buoy1'
2887
2888    buoy = np.ones((N,2), dtype=np.float)*gen.fillValueF
2889
2890    # buoy
2891    N2 = int(N/2)
2892    buoy1v, buoy1vsecs, buoy1vdic = buoy1(height=5., width=10., bradii=1.75, bfrac=0.8, N=N2)
2893    buoy[0:N2,:] = buoy1v
2894
2895    # signs
2896    N3 = N - N2 - 2
2897   
2898    bottsigns = 2.*bradii+height
2899    lsign = height*hsigns
2900    # up
2901    N32 = int(N3/2) 
2902    triu = p_angle_triangle(N=N32)
2903    trib = triu*lsign + [0.,-lsign/2.] 
2904
2905    buoy[N2+1:N2+1+N32,:] = trib + [bottsigns+2.1*lsign,0.]
2906
2907    # down
2908    N323 = N - N32 - N2 - 2
2909
2910    trid = p_angle_triangle(N=N323)
2911    trid = mirror_polygon(trid, 'x')
2912    trib = trid*lsign + [lsign,-lsign/2.] 
2913    buoy[N2+N32+2:N,:] = trib + [bottsigns+0.9*lsign,0.]
2914
2915    # painting it
2916    Height = np.max(buoy1v[:,0])
2917
2918    Ncut, halfdown = cut_ypolygon(buoy1v, yval=Height/3., keep='below')
2919    Ncut, halfbtw = cut_between_ypolygon(buoy1v, yval1=Height/3., yval2=Height*2./3.)
2920    Ncut, halfup = cut_ypolygon(buoy1v, yval=Height*2./3., keep='above')
2921
2922    buoy = ma.masked_equal(buoy, gen.fillValueF)
2923
2924    buoysecs = ['buoy', 'sign1', 'sign2', 'third1', 'third2', 'third3']
2925    buoydic = {'buoy': [buoy[0:N2,:],'-','k',1.5],                                   \
2926      'sign1': [buoy[N2+1:N2+N32+1,:],'-','k',1.5],                                  \
2927      'sign2': [buoy[N2+N32+2:N,:],'-','k',1.5],                                     \
2928      'third1': [halfup, '-', 'k', 1.], 'third2': [halfbtw, '-', '#FFFF00', 1.],     \
2929      'third3': [halfdown, '-', 'k', 1.]}
2930
2931    return buoy, buoysecs, buoydic
2932
2933def south_buoy1(height=5., width=10., bradii=1.75, bfrac=0.8, hsigns=0.7, N=300):
2934    """ Function to draw a South danger buoy using buoy1
2935      height: height of the prism (5., default)
2936      width: width of the prism (10., default)
2937      bradii: radii of the ball (1.75, default)
2938      bfrac: fraction of the ball above the prism (0.8, default)
2939      hisgns: height of the signs [as reg. triangle] as percentage of the height
2940        (0.7, default)
2941      N: total number of points of the buoy (300, default)
2942    """
2943    fname = 'south_buoy1'
2944
2945    buoy = np.ones((N,2), dtype=np.float)*gen.fillValueF
2946
2947    # buoy
2948    N2 = int(N/2)
2949    buoy1v, buoy1vsecs, buoy1vdic = buoy1(height=5., width=10., bradii=1.75, bfrac=0.8, N=N2)
2950    buoy[0:N2,:] = buoy1v
2951
2952    # signs
2953    N3 = N - N2 - 2
2954   
2955    bottsigns = 2.*bradii+height
2956    lsign = height*hsigns
2957    # up
2958    N32 = int(N3/2) 
2959    trid = p_angle_triangle(N=N32)
2960    trid = mirror_polygon(trid, 'x')
2961    trib = trid*lsign + [0.,-lsign/2.] 
2962
2963    buoy[N2+1:N2+1+N32,:] = trib + [bottsigns+2.9*lsign,0.]
2964
2965    # down
2966    N323 = N - N32 - N2 - 2
2967    trid = p_angle_triangle(N=N323)
2968    trid = mirror_polygon(trid, 'x')
2969    trib = trid*lsign + [lsign,-lsign/2.] 
2970    buoy[N2+N32+2:N,:] = trib + [bottsigns+0.9*lsign,0.]
2971
2972    # painting it
2973    Height = np.max(buoy1v[:,0])
2974
2975    Ncut, halfdown = cut_ypolygon(buoy1v, yval=Height/2., keep='below')
2976    Ncut, halfup = cut_ypolygon(buoy1v, yval=Height/2., keep='above')
2977
2978    buoy = ma.masked_equal(buoy, gen.fillValueF)
2979
2980    buoysecs = ['buoy', 'sign1', 'sign2', 'half1', 'half2']
2981    buoydic = {'buoy': [buoy[0:N2,:],'-','k',1.5],                                   \
2982      'sign1': [buoy[N2+1:N2+N32+1,:],'-','k',1.5],                                  \
2983      'sign2': [buoy[N2+N32+2:N,:],'-','k',1.5], 'half1': [halfup, '-', '#FFFF00', 1.], \
2984      'half2': [halfdown, '-', 'k', 1.]}
2985
2986    return buoy, buoysecs, buoydic
2987
2988def west_buoy1(height=5., width=10., bradii=1.75, bfrac=0.8, hsigns=0.7, N=300):
2989    """ Function to draw a West danger buoy using buoy1
2990      height: height of the prism (5., default)
2991      width: width of the prism (10., default)
2992      bradii: radii of the ball (1.75, default)
2993      bfrac: fraction of the ball above the prism (0.8, default)
2994      hisgns: height of the signs [as reg. triangle] as percentage of the height
2995        (0.7, default)
2996      N: total number of points of the buoy (300, default)
2997    """
2998    fname = 'east_buoy1'
2999
3000    buoy = np.ones((N,2), dtype=np.float)*gen.fillValueF
3001
3002    # buoy
3003    N2 = int(N/2)
3004    buoy1v, buoy1vsecs, buoy1vdic = buoy1(height=5., width=10., bradii=1.75, bfrac=0.8, N=N2)
3005    buoy[0:N2,:] = buoy1v
3006
3007    # signs
3008    N3 = N - N2 - 2
3009   
3010    bottsigns = 2.*bradii+height
3011    lsign = height*hsigns
3012
3013    # down
3014    N32 = int(N3/2) 
3015    trid = p_angle_triangle(N=N32)
3016    trid = mirror_polygon(trid, 'x')
3017    trib = trid*lsign + [lsign,-lsign/2.] 
3018    buoy[N2+1:N2+1+N32,:] = trib + [bottsigns+1.9*lsign,0.]
3019
3020    # up
3021    N323 = N - N32 - N2 - 2
3022    triu = p_angle_triangle(N=N323)
3023    trib = triu*lsign + [0.,-lsign/2.] 
3024
3025    buoy[N2+N323+2:N,:] = trib + [bottsigns+1.*lsign,0.]
3026
3027    # painting it
3028    Height = np.max(buoy1v[:,0])
3029
3030    Ncut, halfdown = cut_ypolygon(buoy1v, yval=Height/3., keep='below')
3031    Ncut, halfbtw1 = cut_between_ypolygon(buoy1v, yval1=Height/3., yval2=Height*2./3.)
3032    Ncut, halfup = cut_ypolygon(buoy1v, yval=Height*2./3., keep='above')
3033
3034    buoy = ma.masked_equal(buoy, gen.fillValueF)
3035
3036    buoysecs = ['buoy', 'sign1', 'sign2', 'third1', 'third2', 'third3']
3037    buoydic = {'buoy': [buoy[0:N2,:],'-','k',1.5],                                   \
3038      'third1': [halfdown, '-', '#FFFF00', 1.], 'third2': [halfbtw1, '-', 'k', 1.],  \
3039      'third3': [halfup, '-', '#FFFF00', 1.],                                        \
3040      'sign1': [buoy[N2+1:N2+N32+1,:],'-','k',1.5],                                  \
3041      'sign2': [buoy[N2+N32+2:N,:],'-','k',1.5]}
3042
3043    return buoy, buoysecs, buoydic
3044
3045def safewater_buoy1(height=5., width=10., bradii=1.75, bfrac=0.8, hsigns=0.3, N=300):
3046    """ Function to draw a safe water mark buoy using buoy1
3047      height: height of the prism (5., default)
3048      width: width of the prism (10., default)
3049      bradii: radii of the ball (1.75, default)
3050      bfrac: fraction of the ball above the prism (0.8, default)
3051      hisgns: height of the signs [as reg. triangle] as percentage of the height
3052        (0.3, default)
3053      N: total number of points of the buoy (300, default)
3054    """
3055    fname = 'safewater_buoy1'
3056
3057    buoy = np.ones((N,2), dtype=np.float)*gen.fillValueF
3058
3059    # buoy
3060    N2 = int(N/2)
3061    buoy1v, buoy1vsecs, buoy1vdic = buoy1(height=5., width=10., bradii=1.75,         \
3062      bfrac=0.8, N=N2)
3063    buoy[0:N2,:] = buoy1v
3064
3065    # signs
3066    N3 = N - N2 - 1
3067    lsign = height*hsigns
3068   
3069    Height = np.max(buoy1v[:,0])
3070    sign = p_circle(lsign, N3)
3071    buoy[N2+1:N2+2+N3,:] = sign + [Height+1.2*lsign,0.]
3072
3073    # painting it
3074    ix = -width/2.
3075    Ncut, quarter1 = cut_xpolygon(buoy1v, xval=ix+width/4., keep='left')
3076    Ncut, quarter2 = cut_between_xpolygon(buoy1v, xval1=ix+width/4., xval2=ix+width/2.)
3077    Ncut, quarter3 = cut_between_xpolygon(buoy1v, xval1=ix+width/2., xval2=ix+3.*width/4.)
3078    Ncut, quarter4 = cut_xpolygon(buoy1v, xval=ix+3.*width/4., keep='right')
3079
3080    buoy = ma.masked_equal(buoy, gen.fillValueF)
3081
3082    buoysecs = ['buoy', 'sign', 'quarter1', 'quarter2', 'quarter3', 'quarter4']
3083    buoydic = {'buoy': [buoy[0:N2,:],'-','k',1.5],                                   \
3084      'sign': [buoy[N2+1:N2+N3+1,:],'-','r',1.5], 'quarter1': [quarter1,'-','r',1.], \
3085      'quarter2': [quarter2,'-','#FFFFFF',1.], 'quarter3': [quarter3,'-','r',1.],    \
3086      'quarter4': [quarter4,'-','#FFFFFF',1.]}
3087
3088    return buoy, buoysecs, buoydic
3089
3090def red_buoy1(height=5., width=10., bradii=1.75, bfrac=0.8, hsigns=0.3, N=300):
3091    """ Function to draw a red mark buoy using buoy1
3092      height: height of the prism (5., default)
3093      width: width of the prism (10., default)
3094      bradii: radii of the ball (1.75, default)
3095      bfrac: fraction of the ball above the prism (0.8, default)
3096      hisgns: height of the signs [as reg. triangle] as percentage of the height
3097        (0.3, default)
3098      N: total number of points of the buoy (300, default)
3099    """
3100    fname = 'red_buoy1'
3101
3102    buoy = np.ones((N,2), dtype=np.float)*gen.fillValueF
3103
3104    # buoy
3105    N2 = int(N/2)
3106    buoy1v, buoy1vsecs, buoy1vdic = buoy1(height=5., width=10., bradii=1.75,         \
3107      bfrac=0.8, N=N2)
3108    buoy[0:N2,:] = buoy1v
3109
3110    # signs
3111    N3 = N - N2 - 1
3112    lsign = height*hsigns*2.
3113   
3114    Height = np.max(buoy1v[:,0])
3115    triu = p_angle_triangle(N=N3)
3116    sign = triu*lsign
3117    buoy[N2+1:N2+2+N3,:] = sign + [Height+0.2*lsign,-lsign/2.]
3118
3119    # painting it
3120    buoy = ma.masked_equal(buoy, gen.fillValueF)
3121
3122    buoysecs = ['buoy', 'sign']
3123    buoydic = {'buoy': [buoy[0:N2,:],'-','r',1.5],                                   \
3124      'sign': [buoy[N2+1:N2+N3+1,:],'-','r',1.5]}
3125
3126    return buoy, buoysecs, buoydic
3127
3128def green_buoy1(height=5., width=10., bradii=1.75, bfrac=0.8, hsigns=0.3, N=300):
3129    """ Function to draw a green mark buoy using buoy1
3130      height: height of the prism (5., default)
3131      width: width of the prism (10., default)
3132      bradii: radii of the ball (1.75, default)
3133      bfrac: fraction of the ball above the prism (0.8, default)
3134      hisgns: height of the signs [as reg. triangle] as percentage of the height
3135        (0.3, default)
3136      N: total number of points of the buoy (300, default)
3137    """
3138    fname = 'green_buoy1'
3139
3140    buoy = np.ones((N,2), dtype=np.float)*gen.fillValueF
3141
3142    # buoy
3143    N2 = int(N/2)
3144    buoy1v, buoy1vsecs, buoy1vdic = buoy1(height=5., width=10., bradii=1.75,         \
3145      bfrac=0.8, N=N2)
3146    buoy[0:N2,:] = buoy1v
3147
3148    # signs
3149    N3 = N - N2 - 1
3150    lsign = height*hsigns*2.
3151   
3152    Height = np.max(buoy1v[:,0])
3153    sign = p_prism(lsign, lsign*2, N=N3)
3154    buoy[N2+1:N2+2+N3,:] = sign + [Height+1.2*lsign,0.]
3155
3156    # painting it
3157    buoy = ma.masked_equal(buoy, gen.fillValueF)
3158
3159    buoysecs = ['buoy', 'sign']
3160    buoydic = {'buoy': [buoy[0:N2,:],'-','g',1.5],                                   \
3161      'sign': [buoy[N2+1:N2+N3+1,:],'-','g',1.5]}
3162
3163    return buoy, buoysecs, buoydic
3164
3165def prefchannelportA_buoy1(height=5., width=10., bradii=1.75, bfrac=0.8, hsigns=0.3, \
3166  N=300):
3167    """ Function to draw a preferred channel port system A buoy using buoy1
3168      height: height of the prism (5., default)
3169      width: width of the prism (10., default)
3170      bradii: radii of the ball (1.75, default)
3171      bfrac: fraction of the ball above the prism (0.8, default)
3172      hisgns: height of the signs [as reg. triangle] as percentage of the height
3173        (0.3, default)
3174      N: total number of points of the buoy (300, default)
3175    """
3176    fname = 'prefchannelportA_buoy1'
3177
3178    buoy = np.ones((N,2), dtype=np.float)*gen.fillValueF
3179
3180    # buoy
3181    N2 = int(N/2)
3182    buoy1v, buoy1vsecs, buoy1vdic = buoy1(height=5., width=10., bradii=1.75,         \
3183      bfrac=0.8, N=N2)
3184    buoy[0:N2,:] = buoy1v
3185
3186    # signs
3187    N3 = N - N2 - 1
3188    lsign = height*hsigns*2.
3189   
3190    Height = np.max(buoy1v[:,0])
3191    triu = p_angle_triangle(N=N3)
3192    sign = triu*lsign
3193    buoy[N2+1:N2+2+N3,:] = sign + [Height+0.2*lsign,-lsign/2.]
3194
3195    # painting it
3196    Ncut, third1 = cut_ypolygon(buoy1v, yval=Height/3., keep='below')
3197    Ncut, third2 = cut_between_ypolygon(buoy1v, yval1=Height/3., yval2=Height*2./3.)
3198    Ncut, third3 = cut_ypolygon(buoy1v, yval=Height*2./3., keep='above')
3199
3200    buoy = ma.masked_equal(buoy, gen.fillValueF)
3201
3202    buoysecs = ['buoy', 'sign', 'third1', 'third2', 'third3']
3203    buoydic = {'buoy': [buoy[0:N2,:],'-','r',1.5],                                   \
3204      'sign': [buoy[N2+1:N2+N3+1,:],'-','g',1.5], 'third1': [third1,'-','g',1.5],    \
3205      'third2': [third2,'-','r',1.5], 'third3': [third3,'-','g',1.5]}
3206
3207    return buoy, buoysecs, buoydic
3208
3209def prefchannelportB_buoy1(height=5., width=10., bradii=1.75, bfrac=0.8, hsigns=0.3, \
3210  N=300):
3211    """ Function to draw a preferred channel port system B buoy using buoy1
3212      height: height of the prism (5., default)
3213      width: width of the prism (10., default)
3214      bradii: radii of the ball (1.75, default)
3215      bfrac: fraction of the ball above the prism (0.8, default)
3216      hisgns: height of the signs [as reg. triangle] as percentage of the height
3217        (0.3, default)
3218      N: total number of points of the buoy (300, default)
3219    """
3220    fname = 'prefchannelportB_buoy1'
3221
3222    buoy = np.ones((N,2), dtype=np.float)*gen.fillValueF
3223
3224    # buoy
3225    N2 = int(N/2)
3226    buoy1v, buoy1vsecs, buoy1vdic = buoy1(height=5., width=10., bradii=1.75,         \
3227      bfrac=0.8, N=N2)
3228    buoy[0:N2,:] = buoy1v
3229
3230    # signs
3231    N3 = N - N2 - 1
3232    lsign = height*hsigns*2.
3233   
3234    Height = np.max(buoy1v[:,0])
3235    triu = p_angle_triangle(N=N3)
3236    sign = triu*lsign
3237    buoy[N2+1:N2+2+N3,:] = sign + [Height+0.2*lsign,-lsign/2.]
3238
3239    # painting it
3240    Ncut, third1 = cut_ypolygon(buoy1v, yval=Height/3., keep='below')
3241    Ncut, third2 = cut_between_ypolygon(buoy1v, yval1=Height/3., yval2=Height*2./3.)
3242    Ncut, third3 = cut_ypolygon(buoy1v, yval=Height*2./3., keep='above')
3243
3244    buoy = ma.masked_equal(buoy, gen.fillValueF)
3245
3246    buoysecs = ['buoy', 'sign', 'third1', 'third2', 'third3']
3247    buoydic = {'buoy': [buoy[0:N2,:],'-','r',1.5],                                   \
3248      'sign': [buoy[N2+1:N2+N3+1,:],'-','r',1.5], 'third1': [third1,'-','r',1.5],    \
3249      'third2': [third2,'-','g',1.5], 'third3': [third3,'-','r',1.5]}
3250
3251    return buoy, buoysecs, buoydic
3252
3253def prefchannelstarboardA_buoy1(height=5., width=10., bradii=1.75, bfrac=0.8,        \
3254  hsigns=0.3, N=300):
3255    """ Function to draw a preferred channel starboard system A buoy using buoy1
3256      height: height of the prism (5., default)
3257      width: width of the prism (10., default)
3258      bradii: radii of the ball (1.75, default)
3259      bfrac: fraction of the ball above the prism (0.8, default)
3260      hisgns: height of the signs [as reg. triangle] as percentage of the height
3261        (0.3, default)
3262      N: total number of points of the buoy (300, default)
3263    """
3264    fname = 'prefchannelstarboardA_buoy1'
3265
3266    buoy = np.ones((N,2), dtype=np.float)*gen.fillValueF
3267
3268    # buoy
3269    N2 = int(N/2)
3270    buoy1v, buoy1vsecs, buoy1vdic = buoy1(height=5., width=10., bradii=1.75,         \
3271      bfrac=0.8, N=N2)
3272    buoy[0:N2,:] = buoy1v
3273
3274    # signs
3275    N3 = N - N2 - 1
3276    lsign = height*hsigns*2.
3277   
3278    Height = np.max(buoy1v[:,0])
3279    sign = p_prism(lsign, lsign*2, N=N3)
3280    buoy[N2+1:N2+2+N3,:] = sign + [Height+1.2*lsign,0.]
3281
3282    # painting it
3283    # painting it
3284    Ncut, third1 = cut_ypolygon(buoy1v, yval=Height/3., keep='below')
3285    Ncut, third2 = cut_between_ypolygon(buoy1v, yval1=Height/3., yval2=Height*2./3.)
3286    Ncut, third3 = cut_ypolygon(buoy1v, yval=Height*2./3., keep='above')
3287
3288    buoy = ma.masked_equal(buoy, gen.fillValueF)
3289
3290    buoysecs = ['buoy', 'sign']
3291    buoydic = {'buoy': [buoy[0:N2,:],'-','g',1.5],                                   \
3292      'sign': [buoy[N2+1:N2+N3+1,:],'-','r',1.5], 'third1': [third1,'-','r',1.5],    \
3293      'third2': [third2,'-','g',1.5], 'third3': [third3,'-','r',1.5]}
3294
3295    return buoy, buoysecs, buoydic
3296
3297def prefchannelstarboardB_buoy1(height=5., width=10., bradii=1.75, bfrac=0.8,        \
3298  hsigns=0.3, N=300):
3299    """ Function to draw a preferred channel starboard system B buoy using buoy1
3300      height: height of the prism (5., default)
3301      width: width of the prism (10., default)
3302      bradii: radii of the ball (1.75, default)
3303      bfrac: fraction of the ball above the prism (0.8, default)
3304      hisgns: height of the signs [as reg. triangle] as percentage of the height
3305        (0.3, default)
3306      N: total number of points of the buoy (300, default)
3307    """
3308    fname = 'prefchannelstarboardB_buoy1'
3309
3310    buoy = np.ones((N,2), dtype=np.float)*gen.fillValueF
3311
3312    # buoy
3313    N2 = int(N/2)
3314    buoy1v, buoy1vsecs, buoy1vdic = buoy1(height=5., width=10., bradii=1.75,         \
3315      bfrac=0.8, N=N2)
3316    buoy[0:N2,:] = buoy1v
3317
3318    # signs
3319    N3 = N - N2 - 1
3320    lsign = height*hsigns*2.
3321   
3322    Height = np.max(buoy1v[:,0])
3323    sign = p_prism(lsign, lsign*2, N=N3)
3324    buoy[N2+1:N2+2+N3,:] = sign + [Height+1.2*lsign,0.]
3325
3326    # painting it
3327    # painting it
3328    Ncut, third1 = cut_ypolygon(buoy1v, yval=Height/3., keep='below')
3329    Ncut, third2 = cut_between_ypolygon(buoy1v, yval1=Height/3., yval2=Height*2./3.)
3330    Ncut, third3 = cut_ypolygon(buoy1v, yval=Height*2./3., keep='above')
3331
3332    buoy = ma.masked_equal(buoy, gen.fillValueF)
3333
3334    buoysecs = ['buoy', 'sign']
3335    buoydic = {'buoy': [buoy[0:N2,:],'-','g',1.5],                                   \
3336      'sign': [buoy[N2+1:N2+N3+1,:],'-','g',1.5], 'third1': [third1,'-','g',1.5],    \
3337      'third2': [third2,'-','r',1.5], 'third3': [third3,'-','g',1.5]}
3338
3339    return buoy, buoysecs, buoydic
3340
3341def isolateddanger_buoy1(height=5., width=10., bradii=1.75, bfrac=0.8, hsigns=0.5,   \
3342  N=300):
3343    """ Function to draw an isolated danger buoy using buoy1
3344      height: height of the prism (5., default)
3345      width: width of the prism (10., default)
3346      bradii: radii of the ball (1.75, default)
3347      bfrac: fraction of the ball above the prism (0.8, default)
3348      hisgns: height of the signs [as reg. triangle] as percentage of the height
3349        (0.5, default)
3350      N: total number of points of the buoy (300, default)
3351    """
3352    fname = 'isolateddanger_buoy1'
3353
3354    buoy = np.ones((N,2), dtype=np.float)*gen.fillValueF
3355
3356    # buoy
3357    N2 = int(N/2)
3358    buoy1v, buoy1vsecs, buoy1vdic = buoy1(height=5., width=10., bradii=1.75,         \
3359      bfrac=0.8, N=N2)
3360    buoy[0:N2,:] = buoy1v
3361
3362    # signs
3363    N3 = N - N2 - 2
3364   
3365    bottsigns = 2.*bradii+height
3366    lsign = height*hsigns
3367    # up
3368    N32 = int(N3/2) 
3369    circle = p_circle(lsign/2., N=N32)
3370    trib = circle + [0.,0.] 
3371
3372    buoy[N2+1:N2+1+N32,:] = trib + [bottsigns+3.2*lsign,0.]
3373
3374    # up
3375    N323 = N - N32 - N2 - 2
3376    trid = p_circle(lsign/2., N=N32)
3377    trib = circle + [0.,0.] 
3378    buoy[N2+N32+2:N,:] = trib + [bottsigns+2.*lsign,0.]
3379
3380    # painting it
3381    Height = np.max(buoy1v[:,0])
3382
3383    Ncut, third1 = cut_ypolygon(buoy1v, yval=Height/3., keep='below')
3384    Ncut, third2 = cut_between_ypolygon(buoy1v, yval1=Height/3., yval2=Height*2./3.)
3385    Ncut, third3 = cut_ypolygon(buoy1v, yval=Height*2./3., keep='above')
3386
3387    buoy = ma.masked_equal(buoy, gen.fillValueF)
3388
3389    buoysecs = ['buoy', 'sign1', 'sign2', 'halfk', 'halfy']
3390    buoydic = {'buoy': [buoy[0:N2,:],'-','k',1.5],                                   \
3391      'sign1': [buoy[N2+1:N2+N32+1,:],'-','k',1.5],                                  \
3392      'sign2': [buoy[N2+N32+2:N,:],'-','k',1.5], 'third1': [third1, '-', 'k', 1.],   \
3393      'third2': [third2, '-', 'r', 1.], 'third3': [third3, '-', 'k', 1.]}
3394
3395    return buoy, buoysecs, buoydic
3396
3397def special_buoy1(height=5., width=10., bradii=1.75, bfrac=0.8, hsigns=0.5, N=300):
3398    """ Function to draw an special mark buoy using buoy1
3399      height: height of the prism (5., default)
3400      width: width of the prism (10., default)
3401      bradii: radii of the ball (1.75, default)
3402      bfrac: fraction of the ball above the prism (0.8, default)
3403      hisgns: height of the signs [as reg. triangle] as percentage of the height
3404        (0.5, default)
3405      N: total number of points of the buoy (300, default)
3406    """
3407    fname = 'special_buoy1'
3408
3409    buoy = np.ones((N,2), dtype=np.float)*gen.fillValueF
3410
3411    # buoy
3412    N2 = int(N/2)
3413    buoy1v, buoy1vsecs, buoy1vdic = buoy1(height=5., width=10., bradii=1.75,         \
3414      bfrac=0.8, N=N2)
3415    buoy[0:N2,:] = buoy1v
3416
3417    Height = np.max(buoy1v[:,0])
3418
3419    # sign
3420    N3 = N - N2 - 1
3421   
3422    bottsigns = 2.*bradii+height
3423    lsign = height*hsigns
3424    # up
3425    cross, crosssecs, crossdic = p_cross_width(lsign, width=0.3*lsign, Narms=2, N=N3)
3426    cross = rotate_polygon_2D(cross, 40.05)
3427    buoy[N2+1:N,:] = cross + [Height+1.1*lsign,0.]
3428
3429    # painting it
3430    buoy = ma.masked_equal(buoy, gen.fillValueF)
3431
3432    buoysecs = ['buoy', 'sign']
3433    buoydic = {'buoy': [buoy[0:N2,:],'-','#FFFF00',1.5],                             \
3434      'sign': [buoy[N2+1:N,:],'-','#FFFF00',1.5]}
3435
3436    return buoy, buoysecs, buoydic
3437
3438def emergency_buoy1(height=5., width=10., bradii=1.75, bfrac=0.8, hsigns=0.5, N=300):
3439    """ Function to draw an eergency mark buoy using buoy1
3440      height: height of the prism (5., default)
3441      width: width of the prism (10., default)
3442      bradii: radii of the ball (1.75, default)
3443      bfrac: fraction of the ball above the prism (0.8, default)
3444      hisgns: height of the signs [as reg. triangle] as percentage of the height
3445        (0.5, default)
3446      N: total number of points of the buoy (300, default)
3447    """
3448    fname = 'emergency_buoy1'
3449
3450    buoy = np.ones((N,2), dtype=np.float)*gen.fillValueF
3451
3452    # buoy
3453    N2 = int(N/2)
3454    buoy1v, buoy1vsecs, buoy1vdic = buoy1(height=5., width=10., bradii=1.75,         \
3455      bfrac=0.8, N=N2)
3456    buoy[0:N2,:] = buoy1v
3457
3458    Height = np.max(buoy1v[:,0])
3459
3460    # sign
3461    N3 = N - N2 - 1
3462   
3463    bottsigns = 2.*bradii+height
3464    lsign = height*hsigns
3465    # up
3466    cross, crosssecs, crossdic = p_cross_width(lsign, width=0.3*lsign, Narms=2, N=N3)
3467    buoy[N2+1:N,:] = cross + [Height+1.1*lsign,0.]
3468
3469    # painting it
3470    ix = -width/2.
3471    Ncut, fifth1 = cut_xpolygon(buoy1v, xval=ix+width/5., keep='left')
3472    Ncut, fifth2 = cut_between_xpolygon(buoy1v,xval1=ix+width/5.,xval2=ix+width*2./5.)
3473    Ncut, fifth3 = cut_between_xpolygon(buoy1v,xval1=ix+width*2./5.,xval2=ix+width*3./5.)
3474    Ncut, fifth4 = cut_between_xpolygon(buoy1v,xval1=ix+width*3./5.,xval2=ix+width*4./5.)
3475    Ncut, fifth5 = cut_xpolygon(buoy1v, xval=ix+width*4./5., keep='right')
3476
3477    buoy = ma.masked_equal(buoy, gen.fillValueF)
3478
3479    buoysecs = ['buoy', 'sign', 'fifth1', 'fifth2', 'fifth3', 'fifth4', 'fifth5']
3480    buoydic = {'buoy': [buoy[0:N2,:],'-','#FFFF00',1.5],                             \
3481      'sign': [buoy[N2+1:N,:],'-','#FFFF00',1.5],'fifth1':[fifth1,'-','#FFFF00',1.5],\
3482      'fifth2': [fifth2,'-','#0000FF',1.5],'fifth3': [fifth3,'-','#FFFF00',1.5],     \
3483      'fifth4': [fifth4,'-','#0000FF',1.5],'fifth5': [fifth5,'-','#FFFF00',1.5]}
3484
3485    return buoy, buoysecs, buoydic
3486
3487####### ####### ##### #### ### ## #
3488# Plotting
3489
3490def plot_sphere(iazm=-60., iele=30., dist=10., Npts=100, radii=10,                   \
3491  drwsfc=[True,True], colsfc=['#AAAAAA','#646464'],                                  \
3492  drwxline = True, linex=[':','b',2.], drwyline = True, liney=[':','r',2.],          \
3493  drwzline = True, linez=['-.','g',2.], drwxcline=[True,True],                       \
3494  linexc=[['-','#646400',1.],['--','#646400',1.]],                                   \
3495  drwequator=[True,True], lineeq=[['-','#AA00AA',1.],['--','#AA00AA',1.]],           \
3496  drwgreeenwhich=[True,True], linegw=[['-','k',1.],['--','k',1.]]):
3497    """ Function to plot an sphere and determine which standard lines will be also
3498        drawn
3499      iazm: azimut of the camera form the sphere
3500      iele: elevation of the camera form the sphere
3501      dist: distance of the camera form the sphere
3502      Npts: Resolution for the sphere
3503      radii: radius of the sphere
3504      drwsfc: whether 'up' and 'down' portions of the sphere should be drawn
3505      colsfc: colors of the surface of the sphere portions ['up', 'down']
3506      drwxline: whether x-axis line should be drawn
3507      linex: properties of the x-axis line ['type', 'color', 'wdith']
3508      drwyline: whether y-axis line should be drawn
3509      liney: properties of the y-axis line ['type', 'color', 'wdith']
3510      drwzline: whether z-axis line should be drawn
3511      linez: properties of the z-axis line ['type', 'color', 'wdith']
3512      drwequator: whether 'front' and 'back' portions of the Equator should be drawn
3513      lineeq: properties of the lines 'front' and 'back' of the Equator
3514      drwgreeenwhich: whether 'front', 'back' portions of Greenqhich should be drawn
3515      linegw: properties of the lines 'front' and 'back' Greenwhich
3516      drwxcline: whether 'front', 'back' 90 line (lon=90., lon=270.) should be drawn
3517      linexc: properties of the lines 'front' and 'back' for the 90 line
3518    """
3519    fname = 'plot_sphere'
3520
3521    iazmrad = iazm*np.pi/180.
3522    ielerad = iele*np.pi/180.
3523
3524    # 3D surface Sphere
3525    sfcsphereu, sfcsphered = surface_sphere(radii,Npts)
3526   
3527    # greenwhich
3528    if iazmrad > np.pi/2. and iazmrad < 3.*np.pi/2.:
3529        ia=np.pi-ielerad
3530    else:
3531        ia=0.-ielerad
3532    ea=ia+np.pi
3533    da = (ea-ia)/(Npts-1)
3534    beta = np.arange(ia,ea+da,da)[0:Npts]
3535    alpha = np.zeros((Npts), dtype=np.float)
3536    greenwhichc = spheric_line(radii,alpha,beta)
3537    ia=ea+0.
3538    ea=ia+np.pi
3539    da = (ea-ia)/(Npts-1)
3540    beta = np.arange(ia,ea+da,da)[0:Npts]
3541    greenwhichd = spheric_line(radii,alpha,beta)
3542
3543    # Equator
3544    ia=np.pi-iazmrad/2.
3545    ea=ia+np.pi
3546    da = (ea-ia)/(Npts-1)
3547    alpha = np.arange(ia,ea+da,da)[0:Npts]
3548    beta = np.zeros((Npts), dtype=np.float)
3549    equatorc = spheric_line(radii,alpha,beta)
3550    ia=ea+0.
3551    ea=ia+np.pi
3552    da = (ea-ia)/(Npts-1)
3553    alpha = np.arange(ia,ea+da,da)[0:Npts]
3554    equatord = spheric_line(radii,alpha,beta)
3555
3556    # 90 line
3557    if iazmrad > np.pi and iazmrad < 2.*np.pi:
3558        ia=3.*np.pi/2. + ielerad
3559    else:
3560        ia=np.pi/2. - ielerad
3561    if ielerad < 0.:
3562        ia = ia + np.pi
3563    ea=ia+np.pi
3564    da = (ea-ia)/(Npts-1)
3565    beta = np.arange(ia,ea+da,da)[0:Npts]
3566    alpha = np.ones((Npts), dtype=np.float)*np.pi/2.
3567    xclinec = spheric_line(radii,alpha,beta)
3568    ia=ea+0.
3569    ea=ia+np.pi
3570    da = (ea-ia)/(Npts-1)
3571    beta = np.arange(ia,ea+da,da)[0:Npts]
3572    xclined = spheric_line(radii,alpha,beta)
3573
3574    # x line
3575    xline = np.zeros((2,3), dtype=np.float)
3576    xline[0,:] = position_sphere(radii, 0., 0.)
3577    xline[1,:] = position_sphere(radii, np.pi, 0.)
3578
3579    # y line
3580    yline = np.zeros((2,3), dtype=np.float)
3581    yline[0,:] = position_sphere(radii, np.pi/2., 0.)
3582    yline[1,:] = position_sphere(radii, 3*np.pi/2., 0.)
3583
3584    # z line
3585    zline = np.zeros((2,3), dtype=np.float)
3586    zline[0,:] = position_sphere(radii, 0., np.pi/2.)
3587    zline[1,:] = position_sphere(radii, 0., -np.pi/2.)
3588
3589    fig = plt.figure()
3590    ax = fig.gca(projection='3d')
3591
3592    # Sphere surface
3593    if drwsfc[0]:
3594        ax.plot_surface(sfcsphereu[0,:,:], sfcsphereu[1,:,:], sfcsphereu[2,:,:],     \
3595          color=colsfc[0])
3596    if drwsfc[1]:
3597        ax.plot_surface(sfcsphered[0,:,:], sfcsphered[1,:,:], sfcsphered[2,:,:],     \
3598          color=colsfc[1])
3599
3600    # greenwhich
3601    linev = linegw[0]
3602    if drwgreeenwhich[0]:
3603        ax.plot(greenwhichc[:,0], greenwhichc[:,1], greenwhichc[:,2], linev[0],      \
3604          color=linev[1], linewidth=linev[2],  label='Greenwich')
3605    linev = linegw[1]
3606    if drwgreeenwhich[1]:
3607        ax.plot(greenwhichd[:,0], greenwhichd[:,1], greenwhichd[:,2], linev[0],      \
3608          color=linev[1], linewidth=linev[2])
3609
3610    # Equator
3611    linev = lineeq[0]
3612    if drwequator[0]:
3613        ax.plot(equatorc[:,0], equatorc[:,1], equatorc[:,2], linev[0],               \
3614          color=linev[1], linewidth=linev[2], label='Equator')
3615    linev = lineeq[1]
3616    if drwequator[1]:
3617        ax.plot(equatord[:,0], equatord[:,1], equatord[:,2], linev[0],               \
3618          color=linev[1], linewidth=linev[2])
3619
3620    # 90line
3621    linev = linexc[0]
3622    if drwxcline[0]:
3623        ax.plot(xclinec[:,0], xclinec[:,1], xclinec[:,2], linev[0], color=linev[1],  \
3624          linewidth=linev[2], label='90-line')
3625    linev = linexc[1]
3626    if drwxcline[1]:
3627        ax.plot(xclined[:,0], xclined[:,1], xclined[:,2], linev[0], color=linev[1],  \
3628          linewidth=linev[2])
3629
3630    # x line
3631    linev = linex
3632    if drwxline:
3633        ax.plot([xline[0,0],xline[1,0]], [xline[0,1],xline[1,1]],                    \
3634          [xline[0,2],xline[1,2]], linev[0], color=linev[1], linewidth=linev[2],     \
3635          label='xline')
3636
3637    # y line
3638    linev = liney
3639    if drwyline:
3640        ax.plot([yline[0,0],yline[1,0]], [yline[0,1],yline[1,1]],                    \
3641          [yline[0,2],yline[1,2]], linev[0], color=linev[1], linewidth=linev[2],     \
3642          label='yline')
3643
3644    # z line
3645    linev = linez
3646    if drwzline:
3647        ax.plot([zline[0,0],zline[1,0]], [zline[0,1],zline[1,1]],                    \
3648          [zline[0,2],zline[1,2]], linev[0], color=linev[1], linewidth=linev[2],     \
3649          label='zline')
3650
3651    plt.legend()
3652
3653    return fig, ax
3654
3655def paint_filled(objdic, fillsecs):
3656    """ Function to draw an object filling given sections
3657      objdic: dictionary of the object
3658      filesecs: list of sections to be filled
3659    """
3660    fname = 'paint_filled'
3661
3662    Nsecs = len(fillsecs)
3663
3664    for secn in fillsecs:
3665        secvals=objdic[secn]
3666        pvals = secvals[0]
3667        fillsec = []
3668        Nvals = pvals.shape[0]
3669        for ip in range(Nvals-1):
3670            if type(pvals[ip][0]) != type(gen.mamat[1]) and type(pvals[ip+1][0]) != type(gen.mamat[1]): 
3671                fillsec.append(pvals[ip,:])
3672#        plt.fill(pvals[:,1], pvals[:,0], color=secvals[2])
3673        fillsec = np.array(fillsec)
3674        plt.fill(fillsec[:,1], fillsec[:,0], color=secvals[2])
3675
3676    return
3677
Note: See TracBrowser for help on using the repository browser.