def spline(pts, levels=6, closed=0, iters=20, kk=1.62): """ Calcolo spline interpolante: pts lista dei punti da interpolare levels=6 numero livelli di suddivisione closed=false true se la spline e' chiusa iters=20 numero iterazioni per calcolo interpolazione kk=1.62 coefficiente di rilassamento Il valore di ritorno sono una lista di coordinate. """ return geo2d.splineX(pts, levels, closed, iters, kk)[0]
def complexSplineXP(pts, spigoli, levels=6, closed=0, iters=20, kk=1.62, tipo_spline="CALIGOLA"): """ Calcola una linea complessa: pts lista punti da interpolare spigoli lista degli indici dei punti spigolo levels=6 numero livelli di suddivisione tratti spline closed=false true se la linea e' chiusa iters=20 numero iterazioni per calcolo interpolazione tratti spline kk=1.62 coefficiente di rilassamento tratti spline Restituisce una lista di punti e una lista di tanti interi quanti sono gli elementi di pts che contiene l'indice del punto risultante associato per ciascuno dei punti in ingresso. In input, una linea chiusa deve essere passata *senza* duplicazione del primo/ultimo punto. Nel valore di ritorno, invece, il punto risulterà duplicato. FIXME: potremmo correggere questa asimmetria. La lista di mapping ritornata è sicuramente ordinata, ma può contenere duplicati: infatti, è possibile che due punti geometricamente sovrapposti nella linea di input corrispondano ad un solo punto nella spline di output. """ assert len(spigoli) <= len(pts), \ "Numero di spigoli maggiore di quello dei punti: %r > %r" % (len(spigoli), len(pts)) spigoli = sorted(spigoli) if not closed: # Se la linea e' aperta allora il primo e l'ultimo punto # sono sempre considerati punti spigolo if 0 not in spigoli: spigoli = [0] + spigoli if len(pts)-1 not in spigoli: spigoli = spigoli + [len(pts)-1] if not spigoli: # Linea morbida chiusa, usa una singola spline if tipo_spline == "CALCAD": pts.append(pts[0]) # aggiungo il primo punto in fondo res, ix = geo2d.oldSplineX(pts) else: res, ix = geo2d.splineX(pts, levels, closed, iters, kk) # else: if closed: spigoli = [spigoli[-1]] + spigoli i0 = spigoli.pop(0) res = [pts[i0]] ix = {i0: 0} while spigoli: i1 = spigoli.pop(0) pp = [pts[i0]] ii = [i0] i = (i0 + 1) % len(pts) while i != i1: pp.append(pts[i]) ii.append(i) i = (i + 1) % len(pts) pp.append(pts[i1]) ii.append(i1) if len(pp) == 2: # Tratto rettilineo ix[i1] = len(res) res.append(pts[i1]) else: # Tratto spline if tipo_spline == "CALCAD": if pp[0] == pp[-1]: # se punto iniziale a spigolo pp.append(pp[0]) # aggiungo (ancora) il primo punto in fondo ts, tix = geo2d.oldSplineX(pp) else: ts, tix = geo2d.splineX(pp, levels, 0, iters, kk) for t, i in zip(tix,ii): v = len(res) + t - 1 ix[i] = v res.extend(ts[1:]) i0 = i1 # Ruota per allineare risultato con pts (necessario solo # per spline chiuse con spigoli in cui il primo punto non # sia un punto spigolo) xx = ix[0] if xx > 0: res = res[xx:-1] + res[:xx+1] print 'res s p', len(res) for i in xrange(len(pts)): a = (ix[i] - xx) % len(res) ix[i] = a # A seguito della rotazione, due punti sovrapposti possono risultare # essere il primo e l'ultimo, nel qual caso ix non sarebbe più # ordinata. if ix[len(pts)-1] == 0: ix[len(pts)-1] = len(res)-1 # converte il dict in lista nix = [None] * len(pts) for i, v in ix.items(): nix[i] = v ix = nix sres = [res[0]] six = [ix[0]] # L'algoritmo di semplificazione per tratto funziona solo se ix è ordinata assert sorted(ix) == ix for i in xrange(1, len(ix)): if ix[i-1] != ix[i]: del sres[-1] s = res[ix[i-1]:ix[i]+1] assert len(s) > 0 sres.extend(geo2d.simplify(s)) six.append(len(sres) - 1) if closed: del sres[-1] sres.extend(geo2d.simplify(res[ix[-1]:])) return sres, six