This repository has been archived on 2023-03-25. You can view files and clone it, but cannot push or open issues or pull requests.

188 lines
5.2 KiB
Python

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)