Calcolo dell'orientamento di ciascun lato del poligono utilizzando ArcPy?


9

Voglio esaminare l'orientamento di ciascuna linea in un poligono in modo da poter calcolare la loro esposizione solare. Ogni poligono rappresenta un edificio e ha un'altezza associata. Per il momento, voglio solo prendere in considerazione l'orientamento e in seguito considererò i problemi di ombreggiatura.

Un approccio che ho pensato è stato quello di dividere il poligono in linee e calcolare l'orientamento di ciascuna linea, ma la difficoltà è che devo quindi identificare la faccia esterna di quella linea. Sebbene la maggior parte dei poligoni siano semplici figure a quattro lati con linee rette, esiste un piccolo numero in cui questo non è il caso (un problema che voglio solo considerare, ma non devo ancora risolvere).

Ho familiarità con Python e ho pianificato di farlo tutto da uno script.


1
Le risposte a questa domanda sono di aiuto: gis.stackexchange.com/questions/1886/…
Sean

@Sean - grazie, sì, questo aiuta in generale. Non ho familiarità con i comandi ArcGIS specifici che possono essere utilizzati per farlo. Inoltre, il problema di sapere cosa rimane ancora la faccia interna / esterna della linea in un poligono.
djq

Quando dici "orientamento", non lo hai definito abbastanza bene per me --- qual è l'orientamento di un esagono perfetto, per esempio?
Dan S.

@Dan S. Ho appena modificato la mia risposta per includere l'orientamento di ogni riga nel poligono.
djq,

scusate i rispondenti - ieri non sono riuscito a assegnare correttamente la taglia.
djq,

Risposte:


6

Se vuoi solo un orientamento di maggioranza, dai un'occhiata alla risposta di @Mapperz sopra.

Altrimenti, come dici, potresti dividere i poligoni in linee usando lo strumento Poligono su linea . Ciò aggiunge un campo FID sinistro e destro, in cui il campo è -1 se non è presente un poligono esterno; ciò può causare un po 'di confusione se gli edifici sono adiacenti o si sovrappongono.

Da lì puoi dividere le tue linee in ogni vertice (magari usa Dividi in linee COGO ), quindi calcola gli angoli su ciascuna delle linee (potenzialmente aggiornando gli attributi COGO ).

Supponendo che il tuo campo angolare sia calcolato da nord, l'aspetto sarà corretto dove il FID_ sinistra è -1, e per ottenere l'aspetto quando il FID_fida è -1 basta aggiungere 180 °. Quindi in base al FID originale è possibile aggregare, ottenere l'aspetto maggioritario in base alla lunghezza, ecc.

Lo strumento Poligono per allineare è programmabile, (per quanto ne so) non lo sono gli strumenti COGO, quindi dovresti inventarti qualcosa da solo.

Spero che sia di aiuto!


2
Spina spudorata e un commento: in primo luogo, se non si dispone di una licenza Info, code.google.com/p/boundary-generator fa più o meno lo stesso dello strumento Poligono su linea. Secondo: questo ti dà molte più informazioni rispetto al semplice guardare a una sorta di orientamento generale del poligono generale ... ad esempio puoi usare la tabella risultante per fare calcoli di esposizione al sole molto più precisi, tenendo conto dell'aspetto di ogni singola parete .
Dan S.


5

Trovare l'orientamento

All'interno di uno script, il poligono sarà disponibile come una serie di anelli - un anello esterno e zero o più anelli interni - con ogni anello rappresentato da una tupla di vettori ordinata ciclicamente (v [0], v 1 , ... , v [m-1], v [m] = v [0]). Ogni vettore fornisce le coordinate di un vertice (senza due vertici successivi che coincidono). Da questo è semplice, come altri hanno sottolineato, ottenere vettori normali (cioè vettori perpendicolari alle direzioni del bordo):

n [i] = t (v [i + 1] - v [i]).

L'operazione "t" ruota un vettore di 90 gradi in senso antiorario :

t ((x, y)) = (y, -x).

Sono importanti solo le direzioni di questi vettori normali, quindi ridimensionali per avere unità di lunghezza: un vettore (x, y) viene ridimensionato a (x / s, y / s) dove s = Sqrt (x ^ 2 + y ^ 2) (che è la lunghezza del bordo corrispondente). D'ora in poi, supponiamo che sia stato fatto. Scrivi i componenti dei vettori normali dell'unità risultante come

n [i] = (u [i], v [i]), i = 0, 1, ..., m-1.

Discriminare fuori dall'interno

Come hai notato, questo lascia un'ambiguità direzionale: dovremmo usare n [i] o -n [i]? Quale punta verso l'esterno? Questa domanda equivale a trovare il grado della mappa di Gauss . Per calcolarlo, devi sommare gli angoli in base ai quali le normali direzioni cambiano mentre marcia intorno a un anello. Poiché i vettori normali hanno una lunghezza unitaria, il coseno dell'angolo tra due bordi successivi è

Cos (q_i) = n [i]. n [i + 1] = u [i] * u [i + 1] + v [i] * v [i + 1], i = 0, 1, ..., m-1.

(Definisci n [m] = n [0].)

Il seno dell'angolo tra due spigoli successivi è

Sin (q_i) = n [i]. t (n [i + 1]) = u [i] * v [i + 1] - v [i] * u [i + 1].

(Si noti che questi calcoli richiedono solo somme, differenze e prodotti finora.) L'applicazione della funzione tangente inversa principale (ATan2) a una qualsiasi coppia (coseno, seno) fornisce l'angolo q_i tra -180 e 180 gradi. Sommando questi angoli per i = 0, 1, ..., n-1 produce (fino all'errore in virgola mobile) la curvatura totale dell'anello, che deve essere un multiplo di 360 gradi; per un anello chiuso non autointersecante sarà +360 o -360. Nel primo caso il grado è 1 e nel secondo caso il grado è -1. Le normali sono tutte orientate verso l'esterno quando il grado dell'anello esterno è +1 e i gradi degli anelli interni sono -1. Riorientali anello per anello, secondo necessità, secondo questa regola. Cioè, se il grado di un anello è l'opposto di quello necessario, annulla tutte le normali per quell'anello. Ora puoi procedere con i tuoi calcoli di insolazione.


Grazie per una risposta molto esauriente. Quando dici "All'interno di uno script, il poligono sarà disponibile come set di anelli" come è disponibile il poligono? Sebbene abbia familiarità con alcuni script di Python, non so come interpretare il poligono in questo modo. Lo sto leggendo lentamente e sto cercando di capirlo, ma ho difficoltà a tradurre alcune delle spiegazioni in pseudocodici che posso scrivere.
djq

Alcune note su questa risposta: le tipiche API GIS presenteranno sempre l'esterno di un poligono in ordine antiorario, IIRC, il che significa che non devi fare quella fantasia discriminando l'esterno dall'interno - basta usare le rotazioni in senso orario sugli anelli esterni e in senso antiorario sui fori. Un chiarimento per Celenius: il bit di "set di anelli" è il modo in cui la maggior parte delle API, incluso il pitone di ArcGIS, consentono di scomporre un poligono nei suoi segmenti di linea costituenti - un anello ne è una curva chiusa. Poiché i poligoni possono supportare isole e buchi, potresti avere più anelli ...
Dan S.

@Dan Vorrei che fosse il caso che i GIS mantenessero tali rappresentazioni coerenti. Nel corso degli anni il software ESRI ha oscillato avanti e indietro tra i poligoni orientati negativamente e positivamente, lasciandoli semplicemente non orientati. A questo punto non sono sicuro di fare affidamento anche su dichiarazioni documentate riguardanti il ​​loro approccio attuale: sarei cauto. Costa poco controllare l'orientamento dopo aver già elaborato tutti i bordi di un anello.
whuber

.. beh, per fortuna, ho inserito quel piccolo disclaimer IIRC. ;) Non è così spesso che faccio più cose a livello di geometria nello stack ESRI.
Dan S.

@Dan S. - Sono ancora un po 'poco chiaro su come questo può essere programmato in Python. Ci sono delle linee guida per questo?
djq,

1

Questo può aiutare?


È un documento interessante che hai scavato. Tuttavia, nessuno dei metodi descritti è rilevante per un calcolo dell'esposizione solare (a meno che il calcolo non sia inteso come approssimazione approssimativa, che qui non sembra essere il caso).
whuber

1

/ * Forse questo aiuta:

Azimut - pi / 2 è l'orientamento rivolto verso l'esterno dei lati di un poligono RHR:

Ecco un esempio PostGIS, è possibile creare la tabella bldg117862 usando l'istruzione alla fine. SRID è EPSG 2271 (PA StatePlane North Feet) e la geometria è un multipoligono. Per visualizzare in ArcGIS 10, incollare query / sottoquery in una connessione di livello query a postgis dopo aver creato la tabella bldg117862. * /

- === INIZIO DI QUERY ===

/ * La query esterna fornisce l'orientamento degli ortogonali esterni e crea linee ortogonali esterne di uguale lunghezza come quelle dei lati dal punto medio dei lati.

Le direzioni di orientamento dominanti saranno la somma della lunghezza, raggruppata per orientamento, in ordine decrescente * /

SELEZIONA line_id come side_id, lunghezza, gradi (orthoaz) come orientamento, st_makeline (st_setsrid (st_line_interpolate_point (geom, .5), 2271), st_setsrid (st_makepoint (st_x (st_line_interpolate_point (geom, .5)) + (lunghezza * (sin orthoaz))), st_y (st_line_interpolate_point (geom, .5)) + (lunghezza * (cos (orthoaz)))), 2271)) come geom da

- la subquery esterna successiva crea linee dalle coppie di punti dei lati, calcola l'azimut (ortogonale) dell'ortogonale esterna per ciascun segmento

(SELECT bldg2009gid, line_id, st_length (st_makeline (punto iniziale, punto finale)) :: numerico (10,2) come lunghezza, azimut (punto iniziale, punto finale), azimut (punto iniziale, punto finale) - pi () / 2 come orthoaz, st_makeline ( startpoint, endpoint) come geom da

/ * sottoquery più interna - usa generate_series () per scomporre i poligoni dell'edificio in coppie di punti di inizio / punto finale dei lati - nota1 - forza la regola della mano destra per garantire l'orientamento comune di tutti i lati del poligono nota2 - esempio usa multipoligono, per poligono la geometrian () può essere rimosso * /

(SELECT generate_series (1, npoints (exteriorring (geometryn (st_forceRHR (geom), 1))) - 1) come line_id, gid come bldg2009gid, pointn (exteriorring (geometryn (st_forceRHR (geom), 1)), generate_series (1, npoints (exteriorring (geometryn (st_forceRHR (geom), 1))) - 1)) come punto di partenza, pointn (exteriorring (geometryn (st_forceRHR (geom), 1)), generate_series (2, npoints (exteriorring (geometryn (st_forceRHR (geom) ), 1))))) come endpoint da bldg117862) come t1) come t2

- === FINE DOMANDA ===

- le istruzioni create / insert della tabella bldg117862

IMPOSTA STANDARD_CONFORMING_STRINGS SU ON; SELEZIONA DropGeometryColumn ('', 'bldg117862', 'geom'); DROP TABLE "bldg117862"; INIZIO; CREATE TABLE "bldg117862" (gid serial PRIMARY KEY, "motherpin" varchar (14), "taxpin" varchar (14), "status" varchar (15), "area" numerico, "prev_area" numerico, "pct_change" numerico, "picture" varchar (133), "mappage" varchar (6), "sref_gid" int4, "e_address" varchar (19), "a_address" varchar (19), "perim" numerico, "card" int4, "a_addnum" int4, "e_street" varchar (50), "a_street" varchar (50), "e_hsnum" varchar (10)); SELECT AggiungiGeometryColumn ('', 'bldg117862', 'geom', '2271', 'MULTIPOLYGON', 2); 0106000020DF080000010000000103000020DF080000010000000B0000008C721D6C98AC34415E2C5BB9D3E32541AE56DE17BEAC34410613E5A0A0E325411AB6C794AEAC3441BA392FE372E32541C89C38429DAC3441643857628AE325418C299A9095AC3441F66C29B573E32541983F02087EAC34413080AA9F93E325419BAC3C0A86AC3441AC1F3B3DABE32541803A40B974AC3441E8CF3DB9C2E325413E3758C186AC3441D0AAB0E7F7E325410AAAA5429BAC3441BA971217DCE325418C721D6C98AC34415E2C5BB9D3E32541' ); CREA INDICE "bldg117862_geom_gist" ON "bldg117862" usando gist ("geom" gist_geometry_ops); FINE;


0

Supponendo che l'orientamento dei segmenti di linea sia costante in un poligono, è possibile calcolare il rilevamento (direzione) di un vettore perpendicolare a ciascun segmento di linea. Non ho tempo in questo momento per cercare il codice, ma se hai bisogno di matematica, può essere facilmente fornito :-)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.