2015-01-19 10 views
7

Ho un caso che si basa sulla proiezione di un punto su una linea e quindi separare questa linea su di esso. Il mio caso d'uso è un po 'più complicato, ma il mio problema può essere riprodotto con il seguente codice:Come gestire gli errori di arrotondamento in Shapely

from shapely import * 
line1 = LineString([(1,1.2), (2,2), (3, 2.), (4,1.2)]) 
pt = Point(2.5, 1.2) 
pr = line1.interpolate(line1.project(pt)) 

Per costruzione, "pr" dovrebbe essere accesa linea 1 e la loro intersezione troppo:

line1.contains(pr) 
line1.intersects(LineString([pt, pr])) 

stampe due volte "Vere". Ma cambiare l'ingresso coordina un po 'i freni del flusso di lavoro:

from shapely import * 
line1 = LineString([(1,1.2), (2,2), (3, 2.3), (4,1.2)]) 
pt = Point(2.5, 1.2) 
pr = line1.interpolate(line1.project(pt)) 
line1.contains(pr) 
line1.intersects(LineString([pt, pr])) 

stampe "False".

Capisco il problema di precisione flottante, ma ciò significa che non riesco a eseguire il test per i punti sulle linee? Quando costruisco una linea basata su un elenco di punti, posso essere sicuro che almeno tutti i punti "di costruzione" saranno sulla linea?

+0

Sei in grado di scegliere un'unità più granulare, diciamo, millimetri invece di metri? –

+0

@PauloScardine: grazie. Sì, posso facilmente dare una certa precisione se ottengo stabilità. Moltiplicare i miei valori di 10 rende il trucco. Funzionerà in ** tutti ** i casi? Shapely continua a lavorare con i galleggianti internamente. – Fabzi

risposta

5

Fondamentalmente, è necessario un precision model, e ci sono vari piani per implementarlo in GEOS in un determinato momento (non trattenere il respiro, poiché è in discussione da diversi anni).

In caso contrario, le opzioni sono test basati sulla distanza (consigliato) o tecniche di buffer basata su più costose di un piccolo aggiustamento (vedi machine epsilon):

from shapely.geometry import LineString, Point 

line1 = LineString([(1,1.2), (2,2), (3, 2.3), (4,1.2)]) 
pt = Point(2.5, 1.2) 
pr = line1.interpolate(line1.project(pt)) 

# Distance based 
print(line1.distance(pr) == 0.0) # True 

# Buffer based 
EPS = 1.2e-16 
print(line1.buffer(EPS).contains(pr)) # True 
print(line1.buffer(EPS).intersects(LineString([pt, pr]))) # True 

È inoltre possibile concatenare i test più economici e costosi usando un or operator , per esempio:

print(line1.contains(pr) or line1.buffer(EPS).contains(pr)) 

che corre solo il secondo e più costoso di prova se il primo ritorna False.

+0

Ciao @MikeT, grazie per la tua risposta, questo è ciò di cui avevo paura. Vorrei davvero che avessimo un modello di precisione. O il trucco di lavorare con numeri interi invece di float (vedi il commento di Paulo sopra) garantisce stabilità? Il mio caso d'uso è più complicato e basato sui sindacati: 'shapely.ops.polygonize (LinearRing (line1) .union (LineString ([pt, pr]))) restituisce poligoni diversi se le due linee si intersecano o no ... _ (Vorrei poter revocare la tua risposta, ma non ho abbastanza reputazione per questo;) _ – Fabzi