import numpy import sys from shaperrec import groups from shaperrec import geometric from shaperrec import internal # ************************************************************* # debugging def void(*l): pass def debug_on(*l): sys.stderr.write(' '.join(str(i) for i in l) +'\n') debug = void #debug = debug_on # ************************************************************* # Object manipulation functions def toRemarkableShape( group ): """Test if PathGroup instance 'group' looks like a remarkable shape (ex: Rectangle). if so returns a new shape instance else returns group unchanged""" r = groups.Rectangle.isRectangle( group ) if r : return r return group def resetPrevNextSegment(segs): for i, seg in enumerate(segs[:-1]): s = segs[i+1] seg.next = s s.prev = seg return segs def fitSingleSegment(a): xmin, ymin, w, h = geometric.computeBox(a) inverse = w<h if inverse: a = numpy.roll(a, 1, axis=1) seg = regLin(a) if inverse: seg.inverse() #a = numpy.roll(a,1,axis=0) return seg def regLin(a , returnOnlyPars=False): """perform a linear regression on 2dim array a. Creates a segment object in return """ sumX = a[:, 0].sum() sumY = a[:, 1].sum() sumXY = (a[:, 1]*a[:, 0]).sum() a2 = a*a sumX2 = a2[:, 0].sum() sumY2 = a2[:, 1].sum() N = a.shape[0] pa = (N*sumXY - sumX*sumY)/ ( N*sumX2 - sumX*sumX) pb = (sumY - pa*sumX) /N if returnOnlyPars: return pa, -1, pb return internal.Segment(pa, -1, pb, a) def smoothArray(a, n=2): count = numpy.zeros(a.shape) smootha = numpy.array(a) for i in range(n): count[i]=n+i+1 count[-i-1] = n+i+1 count[n:-n] = n+n+1 #debug('smooth ', len(smooth[:-2]) [) for i in range(1, n+1): smootha[:-i] += a[i:] smootha[i:] += a[:-i] return smootha/count def buildTangents( points , averaged=True, isClosing=False): """build tangent vectors to the curve 'points'. if averaged==True, the tangents are averaged with their direct neighbours (use case : smoother tangents)""" tangents = numpy.zeros( (len(points), 2) ) i=1 tangents[:-i] += points[i:] - points[:-i] # i <- p_i+1 - p_i tangents[i:] += points[i:] - points[:-i] # i <- p_i - p_i-1 if isClosing: tangents[0] += tangents[0] - tangents[-1] tangents[-1] += tangents[0] - tangents[-1] tangents *= 0.5 if not isClosing: tangents[0] *=2 tangents[-1] *=2 ## debug('points ', points) ## debug('buildTangents --> ', tangents ) if averaged: # average over neighbours avTan = numpy.array(tangents) avTan[:-1] += tangents[1:] avTan[1:] += tangents[:-1] if isClosing: tangents[0]+=tangents[-1] tangents[1]+=tangents[0] avTan *= 1./3 if not isClosing: avTan[0] *=1.5 avTan[-1] *=1.5 return avTan def clusterAngles(array, dAng=0.15): """Cluster together consecutive angles with similar values (within 'dAng'). array : flat array of angles returns [ ..., (indi_0, indi_1),...] where each tuple are indices of cluster i """ N = len(array) closebyAng = numpy.zeros( (N, 4), dtype=int) for i, a in enumerate(array): cb = closebyAng[i] cb[0] =i cb[2]=i cb[3]=i c=i-1 # find number of angles within dAng in nearby positions while c>-1: # indices below i d=geometric.closeAngleAbs(a, array[c]) if d>dAng: break cb[1]+=1 cb[2]=c c-=1 c=i+1 while c<N-1:# indices above i d=geometric.closeAngleAbs(a, array[c]) if d>dAng: break cb[1]+=1 cb[3]=c c+=1 closebyAng= closebyAng[numpy.argsort(closebyAng[:, 1]) ] clusteredPos = numpy.zeros(N, dtype=int) clusters = [] for cb in reversed(closebyAng): if clusteredPos[cb[0]]==1: continue # try to build a cluster minI = cb[2] while clusteredPos[minI]==1: minI+=1 maxI = cb[3] while clusteredPos[maxI]==1: maxI-=1 for i in range(minI, maxI+1): clusteredPos[i] = 1 clusters.append( (minI, maxI) ) return clusters def adjustAllAngles(paths): for p in paths: if p.isSegment() and p.newAngle is not None: p.adjustToNewAngle() # next translate to fit end points tr = numpy.zeros(2) for p in paths[1:]: if p.isSegment() and p.prev.isSegment(): tr = p.prev.pointN - p.point1 debug(' translating ', p, ' prev is', p.prev, ' ', tr, ) p.translate(tr) def adjustAllDistances(paths): for p in paths: if p.isSegment() and p.newLength is not None: p.adjustToNewDistance() # next translate to fit end points tr = numpy.zeros(2) for p in paths[1:]: if p.isSegment() and p.prev.isSegment(): tr = p.prev.pointN - p.point1 p.translate(tr)