Suite

Joindre seulement si une ligne de ligne coupe le tampon. Ne pas faire si deux

Joindre seulement si une ligne de ligne coupe le tampon. Ne pas faire si deux


J'ai un réseau routier (entités linéaires) et un trajet de points GPS. Je veux joindre les attributs du réseau routier à chaque point. Donc, pour chaque point, je crée un tampon. Si le tampon croise une entité linéaire, les attributs sont écrits sur le point. Ce n'est pas un problème. Cependant, je ne veux pas écrire d'attributs sur des points si le tampon croise jusqu'à ou plusieurs lignes. Des idees pour faire cela? Je travaille sous ArcGIS. Existe-t-il un moyen de le faire sans utiliser python?


Ceci peut être réalisé en plusieurs étapes.

  1. Exécutez une jointure spatiale pour vos polygones tampons et vos couches de réseau routier (cliquez avec le bouton droit sur la couche de polygones tampons dans la table des matières et choisissez Join and Relates > Join).

Vous obtiendrez une classe d'entités surfaciques en sortie qui contient des informations sur le nombre d'entités routières situées (même partiellement) dans les polygones tamponnés.

  1. Exécutez une jointure entre la classe d'entités en sortie obtenue à l'étape 1 et la couche de polygones tamponnés source pour déterminer les entités que vous ne souhaitez pas prendre en compte dans l'analyse (lorsque vous exécutez Intersection et copiez les attributs).

  2. Configurez une requête de définition ou effectuez une sélection > exportez les données vers une nouvelle classe d'entités lorsque vous avez sélectionné les entités qui ont des valeurs nulles ou 1 (qui sont valides dans votre cas) dans le champ Nombre.

Si vous utilisez ModelBuilder pour automatiser le flux de travail, veuillez utiliser l'outil Add Join GP et l'outil Spatial Join GP.


La division d'un polygone auto-sécant n'a renvoyé qu'un seul polygone dans Shapely

J'utilise Python 3.5 64 bits dans Windows 7 64 bits, la version élégante 1.5.13.

J'ai le code suivant qui m'a renvoyé un polygone à auto-intersection :

C'est correct. Ensuite, j'ai essayé d'obtenir les deux polygones individuels en utilisant buffer(0) :

Malheureusement, il n'est revenu que des deux polygones :

Quelqu'un pourrait-il s'il vous plaît aider? Merci!


Laissez les extrémités du segment de ligne être $vec

_1 = (x_1 , y_1)$ et $vec

_2 = (x_2 , y_2)$ , et la ligne passe par des points $vec

_3 = (x_3 , y_3)$ et $vec

_4 = (x_4 , y_4)$ . Alors, si et seulement si $Bigl((vec

_4 - vec

_3) fois (vec

_1 - vec

_3) Bigr) Bigl( (vec

_4 - vec

_3) fois (vec

_2 - vec

_3) Bigr) le 0$ le segment de ligne coupe-t-il la ligne. Sous forme de coordonnées cartésiennes, $Bigl( (x_4 - x_3)(y_1 - y_3) - (x_1 - x_3)(y_4 - y_3) Bigr) Bigl( (x_4 - x_3)(y_2 - y_3) - (x_2 - x_3)(y_4 - y_3) Bigr) le 0$ Le signe du premier multiplicande dépend de quel côté $vec

_1$ est à la ligne, et le signe du deuxième multiplicande dépend de quel côté $vec

_2$ est à la ligne. Si le produit est nul, $vec

_1$ et/ou $vec

_2$ est en ligne. Si le produit est négatif, alors les deux points doivent se trouver sur des côtés différents de la ligne.

Si les deux points se trouvent sur des côtés différents de la ligne (infiniment longue), alors le segment de ligne doit couper la ligne. Si les deux points sont du même côté, le segment de ligne ne peut pas couper la ligne.


2 réponses 2

Pour plus de simplicité, utilisons $egin ( p_x , p_y , p_z ) = vec

_0 ( d_x , d_y , d_z ) = vec ( a_x , a_y , a_z ) = vec ( b_x , b_y , b_z ) = vec finir$

Si les trois dénominateurs sont nuls, la ligne et le segment de ligne ne se coupent pas. (Cela peut également se produire si $vec

_0 = vec$ ou $vec = vec$ ou les deux.)

Notez que les formules correspondantes pour $s$ ont les mêmes dénominateurs, c'est-à-dire que $eqref<1>$ et $eqref<4>$ ont les mêmes dénominateurs, $eqref<2>$ et $eqref<5> $ ont les mêmes dénominateurs, et $eqref<3>$ et $eqref<6>$ ont les mêmes dénominateurs. (Cela signifie que si une solution pour $t$ existe, une solution existe également pour $s$. Dans le cas d'OP, $s$ n'a pas d'importance, car c'est le paramètre d'une ligne infinie, et tout réel $s$ est acceptable .)


4 réponses 4

Pour le cas 2D, je pense que le problème se simplifie un peu.

La ligne divise l'espace en deux régions.

Si le polygone est présent dans une seule de ces régions, la ligne ne l'intersecte pas.

Si le polygone est présent dans les deux régions, la ligne l'intersecte.

Prenez n'importe quelle perpendiculaire à la ligne, en faisant de l'intersection avec la ligne l'origine.

Projetez chaque sommet du polytope sur la perpendiculaire.

Si ces projections se produisent avec les deux signes, le polygone coupe la ligne.

[Mise à jour suite au commentaire d'elexhobby.]

J'ai oublié d'inclure le traitement du cas illimité.

Je voulais ajouter que l'on pouvait créer un "sommet virtuel" pour représenter la zone ouverte. Ce dont nous avons vraiment besoin, c'est de la "direction" de l'espace ouvert. Nous pouvons prendre cela comme la moyenne des vecteurs pour les bords englobants de la zone ouverte.

Nous traitons ensuite le produit scalaire de cette direction avec la normale et l'ajoutons à l'ensemble des projections de sommets.

En géométrie, voir généralement wikipedia un polygone est délimité. Ce que vous décrivez est généralement appelé un polytope ou un polyèdre voir wikipedia

Il existe quelques bibliothèques de géométrie disponibles, deux qui me viennent à l'esprit sont boost (polygone) et CGAL. En règle générale, il existe une distinction nette entre les méthodes de calcul qui traitent du 2d, du 3d et du N-d - pour des raisons évidentes.

Pour votre problème, j'utiliserais une approche d'arbre de partitionnement d'espace binaire quelque peu. Je prendrais la première ligne de votre "poly" et couperais la ligne de requête contre elle, créant un rayon. Le rayon commencerait à l'intersection des deux lignes, et continuerait en direction de l'intérieur du demi-espace généré par la première ligne du "poly". Maintenant, je répéterais la procédure avec le rayon et la deuxième ligne du "poly". (cela pourrait générer un segment au lieu d'un rayon) Si à un moment donné l'origine du rayon (ou maintenant du segment) se trouve sur le côté extérieur d'une ligne poly actuellement considérée et ne la coupe pas, alors la réponse est non - la ligne ne se coupe pas votre "poly". Sinon il se croise. Faites particulièrement attention aux différents cas de bords parallèles. Assez simple et fonctionne pour les cas multidimensionnels.


2 réponses 2

C'est une méthode coûteuse et a commencé à produire des problèmes de performance. Quel serait l'algorithme recommandé pour ce problème? Existe-t-il un exemple de code ?

Cela dépend beaucoup de la façon dont vous représentez la ligne elle-même. Il semble que vous utilisiez une ligne brisée, c'est-à-dire une juxtaposition de lignes droites.

La première idée qui me vient à l'esprit est de faire une simple vérification de région. Vous pouvez emballer chaque ligne dans un petit rectangle (son cadre englobant) et il est très facile de vérifier si deux cadres englobants se chevauchent ou non - vous pouvez le faire en faisant quelques soustractions, ce qui est beaucoup moins cher que de calculer un déterminant ! Si la vérification de la région échoue, les lignes ne se coupent certainement pas, vous n'avez donc pas besoin de calculer le déterminant.

Avec cela, vous devriez passer de la complexité (nˆ4) à (nˆ2) où n est le nombre de petites lignes droites dans votre ligne.

Si cela ne suffit pas, une deuxième technique courante consiste à diviser le canevas en régions et à représenter cette région sous la forme d'un arbre binaire. Vous commencez avec la toile complète, puis vous coupez en deux, puis vous subdivisez chaque moitié en deux, encore et encore, jusqu'à ce que vous atteigniez un nombre de divisions que vous choisissez à l'avance. (Vous pouvez effectuer des tests empiriques pour déterminer une valeur adaptée à vos données.) Ensuite, vous pouvez attacher chaque segment de ligne à une région où sa boîte englobante s'adapte - Généralement une feuille, mais il peut s'agir d'un nœud de niveau supérieur si un segment de ligne coupe un frontière de la région. Une fois que vous avez compacté chaque segment de ligne dans l'arborescence des régions, il est facile de récupérer voisins d'une ligne de segment, où l'intersection peut avoir lieu.

Ceci est à l'origine un commentaire demandant des éclaircissements, mais il est trop long pour tenir. J'ai donc posté chaque question ici, ainsi que mes réponses "et si" pour chaque question en fonction des réponses possibles.

Avant de chercher des éclaircissements, chacun doit voir que l'implémentation actuelle a une complexité temporelle quadratique en nombre de waypoints. La notation est O(N^2) .

Pour faire simple, si le nombre de waypoints est doublé (augmenté à deux fois), le temps d'exécution sera approximativement quadruplé (augmenté à quatre).

(1) Quel est le nombre typique de points de cheminement que vous devez gérer ? S'il n'y a pas de nombre type, indiquez le nombre maximum possible de points de cheminement que votre code doit prendre en charge.

Par exemple, si vous constatez que le problème de performances ne se produit pas lorsque N (nombre de points de cheminement) est inférieur à plusieurs centaines, vous pouvez imposer une restriction logicielle selon laquelle le mouvement de la souris ne peut pas dépasser ce nombre de pixels. Que cela soit acceptable ou non dépend de l'objectif de votre logiciel.

(2) Êtes-vous autorisé à utiliser des techniques de simplification de ligne pour réduire le nombre de points de cheminement avant de vérifier les intersections ?

La technique de simplification de ligne peut réduire le nombre de points de cheminement par dix (un dixième) ou plus (moins), lorsque le mouvement de la souris est utilisé comme entrée. L'utilisateur devra déplacer la souris très frénétiquement pour faire échouer cette réduction.

(3) Savez-vous comment implémenter et utiliser QuadTree par vous-même ?

Un quadtree permet une requête de cas moyen O (log N) dans une collection (arbre) de cadres de délimitation qui se chevauchent avec le cadre de délimitation de la requête. Pour trouver toutes les boîtes englobantes qui se chevauchent par paires, il faut d'abord y ajouter toutes les boîtes englobantes, puis effectuer une requête sur chaque boîte englobante. Cela donne un total qui est le cas moyen O(N log N) , ce qui est meilleur que l'implémentation d'origine qui est O(N^2) .

(4) Quelle est la largeur et la hauteur de la zone de mouvement, mesurées en pixels, que vous devez prendre en charge ?

Si la zone de mouvement totale (en pixels au carré, c'est-à-dire le produit de la largeur et de la hauteur) est inférieure à quelques millions, et si l'on est autorisé à allouer un tableau pouvant contenir quelques millions d'octets (ou de bits - nous n'avons besoin que de chaque élément à vrai ou faux), alors on peut allouer un tel tableau pour agir comme un bitmap (littéralement une carte de bits).

Le bitmap sera initialisé avec false. Ensuite, lorsque l'utilisateur "peint" avec le mouvement de la souris, les pixels correspondants dans le bitmap seront définis sur vrai.

Caveat. Notez que si la piste de pixels de l'utilisateur n'a qu'un seul pixel (1 sur 1) de large, le cas de contour suivant se produira :

Supposons que la trace aille de (10, 10) à (11, 11) . Plus tard dans la trace, il traverse ce segment en allant (10, 11) à (11, 10) . Étant donné que les pixels eux-mêmes ne se chevauchent pas, ce schéma basé sur des bitmaps ne parviendra pas à détecter une intersection de ce type.

La solution à la mise en garde est que l'on doit vérifier un voisinage 3 par 3 pour les pixels qui avaient été peints auparavant. En faisant cela, il faut également se rappeler d'ignorer les pixels qui viennent d'être peints fraîchement. Il est possible que l'on doive utiliser un octet par pixel (par opposition à un bit par pixel) afin de stocker des informations supplémentaires pour aider à contourner cette mise en garde.


Malheureusement, la mauvaise réponse a été votée. Il est beaucoup trop coûteux de calculer les points d'intersection réels, vous n'avez besoin que de comparaisons. Le mot-clé à rechercher est "Line Clipping" (http://en.wikipedia.org/wiki/Line_clipping). Wikipedia recommande l'algorithme de Cohen-Sutherland (http://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland) lorsque vous souhaitez des rejets rapides, ce qui est probablement le scénario le plus courant. Il y a une implémentation C++ sur la page wikipedia. Si vous n'êtes pas intéressé à couper la ligne, vous pouvez en sauter la majeure partie. La réponse de @Johann ressemble beaucoup à cet algorithme, mais je ne l'ai pas regardée en détail.

Vérifiez d'abord si le rect est à gauche ou à droite des extrémités de la ligne :

  • Établir les valeurs X les plus à gauche et à droite des extrémités de ligne : XMIN et XMAX
  • Si Rect.Left > XMAX, alors pas d'intersection.
  • Si Rect.Right < XMIN, alors pas d'intersection.

Ensuite, si ce qui précède n'est pas suffisant pour exclure une intersection, vérifiez si le rect est au-dessus ou en dessous des extrémités de la ligne :

  • Établir les valeurs Y les plus hautes et les plus basses des extrémités de ligne : YMAX et YMIN
  • Si Rect.Bottom > YMAX, alors pas d'intersection.
  • Si Rect.Top < YMIN, alors pas d'intersection.

Ensuite, si ce qui précède n'était pas suffisant pour exclure une intersection, vous devez vérifier l'équation de la ligne, y = m * x + b , pour voir si le rect est au-dessus de la ligne :

  • Établir la valeur Y de la ligne à Rect.Left et Rect.Right : LINEYRECTLEFT et LINEYRECTRIGHT
  • Si Rect.Bottom > LINEYRECTRIGHT && Rect.Bottom > LINEYRECTLEFT, alors aucune intersection.

Ensuite, si ce qui précède n'est pas suffisant pour exclure une intersection, vous devez vérifier si le rect est en dessous de la ligne :

N.B. Je suis sûr qu'il existe une solution algébrique plus élégante, mais effectuer ces étapes géométriquement avec un stylo et du papier est facile à suivre.

Du code non testé et non compilé pour aller avec :

Ce code a de meilleures performances :

Vous pouvez également vérifier comment cela fonctionne dans la démo JS : http://jsfiddle.net/77eej/2/

Si vous avez deux Points et Rect, vous pouvez appeler cette fonction comme ça :

J'ai pris la solution de HABJAN, qui a bien fonctionné, et je l'ai convertie en Objective-C. Le code Objective-C est le suivant :

Merci beaucoup HABJAN. Je noterai qu'au début, j'ai écrit ma propre routine qui vérifiait chaque point le long du gradient, et j'ai fait tout ce que je pouvais pour maximiser les performances, mais cela a été immédiatement beaucoup plus rapide.

Il n'y a pas de méthode .NET prédéfinie simple que vous pouvez appeler pour accomplir cela. Cependant, en utilisant l'API Win32, il existe un moyen assez simple de le faire (facile au sens de la mise en œuvre, la performance n'est pas le point fort) : LineDDA

Cette fonction appelle la fonction de rappel pour chaque pixel de la ligne à dessiner. Dans cette fonction, vous pouvez vérifier si le pixel est dans votre rectangle - si vous en trouvez un, alors il se coupe.

Comme je le dis, ce n'est pas la solution la plus rapide, mais assez facile à mettre en œuvre. Pour l'utiliser en C#, vous devrez bien entendu le ddlimporter depuis gdi32.dll.

La technique de géométrie computationnelle la plus simple consiste simplement à parcourir les segments du polygone et à voir s'il les croise, car il doit alors également croiser le polygone.

Le seul inconvénient de cette méthode (et de la plupart des CG) est que nous devons faire attention aux cas extrêmes. Que se passe-t-il si la ligne traverse le rectangle en un point - comptons-nous cela comme une intersection ou non ? Soyez prudent dans votre mise en œuvre.

Éditer: L'outil typique pour le calcul ligne-intersection-segment est un test LeftOf(Ray, Point), qui renvoie si le point est à gauche du rayon. Étant donné une ligne l (que nous utilisons comme rayon) et un segment contenant les points a et b , la ligne coupe le segment si un point est à gauche et un autre ne l'est pas :

Encore une fois, vous devez faire attention aux cas limites, lorsque le point est sur la ligne, mais cela dépend de la façon dont vous souhaitez réellement définir l'intersection.


Notez que si le plan est parallèle à L, alors le vecteur normal au plan est alors perpendiculaire à la ligne. Trouvez le vecteur / (a) normal au plan, puis vous avez deux points dans le plan, et vous avez terminé.

Et il y a une infinité de plans qui passent par deux points donnés, il y a une infinité de plans qui passent même par une ligne donnée. Une fois que vous avez un vecteur normal au plan et deux points dans le plan, vous avez terminé (bien que, étant donné deux points, vous puissiez trouver N en utilisant leur produit vectoriel.)

Si la ligne se trouve dans le plan, vous pouvez translater le plan pour éviter de contenir la ligne.


2 réponses 2

Vous aurez besoin d'une liste de contours actifs, qui contient une liste de tous les contours de polygones coupés par la ligne de balayage actuelle. Vous aurez également besoin d'un indicateur d'entrée/sortie pour chaque polygone sur la ligne de balayage. Les drapeaux sont activés/désactivés lorsque vous traversez une arête pour un polygone.

Les règles de dessin pour chaque pixel le long d'une ligne de balayage sont

  1. aucun drapeau de polygone n'est "in", puis dessinez l'arrière-plan
  2. un seul drapeau de polygone est 'in', le dessin de la couleur de ce polygone
  3. deux ou plusieurs drapeaux de polygone sont « in », utilisez votre équation de plan pour savoir lequel est le plus proche à cette position de pixel.
  4. lorsque nous passons au pixel suivant, vérifiez l'AEL (voir ci-dessous) pour voir si nous traversons un bord. si c'est le cas, activez le drapeau approprié.

Un élément important de la structure de données nécessaire à cet algorithme est le nœud périphérique. Chaque bord du polygone est représenté par un nœud de bord. Un nœud périphérique contient les informations suivantes

  1. yupper , la coordonnée y de l'extrémité supérieure de l'arête.
  2. ylower , la coordonnée y de l'extrémité inférieure de l'arête.
  3. xint , initialement la coordonnée x du point d'extrémité inférieur de l'arête. Au fur et à mesure que l'algorithme progresse, ce champ stockera la coordonnée x du point d'intersection de la ligne de balayage.
  4. ym , l'inverse de la pente de la droite ( 1/m ).
  5. lien vers le polygone qui possède le bord.

Lors de la construction d'un nœud de bord pour les bords, les éléments suivants doivent être pris en compte

  1. Les arêtes horizontales sont ignorées (aucun nœud d'arête n'est généré pour celles-ci), ces arêtes seront dessinées lors du traitement des arêtes adjacentes.
  2. Si deux arêtes partagent un sommet ET que le sommet est un point d'extrémité supérieur pour une arête et un point d'extrémité inférieur pour une autre arête, le yupper de l'arête inférieure doit être réduit de 1. ceci permet à la bascule entrée/sortie de fonctionner correctement .

Dans l'image ci-dessus, la ligne de balayage tout en haut croise les bords au sommet du triangle. les deux bords le font basculer de "out" à "in" à "out", ce qui est correct. Cependant, la deuxième ligne coupe également deux bords et est désactivée, ce qui est incorrect. La solution est d'abaisser le y-int du bord inférieur dans ce cas. Maintenant, la ligne de balayage ne coupe qu'une arête au sommet.

Cet ajustement n'aura aucun effet sur la forme du triangle car le xint sera utilisé pour déterminer par où commencer le dessin. L'abaissement du sommet a pour effet de le supprimer une ligne de balayage plus tôt qu'il ne le ferait autrement. Tout cela en supposant que vous numérisez de bas en haut.

La plupart des implémentations maintiennent une liste de bords actifs (AEL), une liste de bords. qui contient tous les bords coupés par la ligne de balayage courante. L'AEL doit être maintenue lorsque nous passons de la ligne de balayage y à la ligne de balayage suivante (y+1)


&& vs ST_Intersects performances

J'essaie de comprendre que les points résident à l'intérieur d'une zone rectangulaire (enveloppe). J'ai un peu de mal à comprendre les implications en termes de performances de l'utilisation de l'opérateur && par rapport à ST_Intersect .

Cependant, je pense avoir expliqué ma propre question en essayant de formuler ma question. Je le soumets quand même au cas où il serait utile à quelqu'un.

Le manuel de && dit (ironiquement, le nom de la page est geometry_overlaps.html):

&& — Renvoie VRAI si le cadre de délimitation 2D de A coupe le cadre de délimitation 2D de B.`

Renvoie VRAI si les géométries/géographies "se croisent spatialement en 2D" - (partagent une partie de l'espace) et FAUX si elles ne le font pas (elles sont disjointes). Pour la géographie -- la tolérance est de 0,00001 mètre (ainsi, tous les points qui se ferment sont considérés comme se coupant)

ST_Intersects retournera vrai dans de tels cas. Pour mon objectif, l'opérateur && fait presque la même chose puisque j'utilise une boîte englobante rectangulaire dans les deux cas. Je me demande si && est l'opérateur le plus rapide pour mon objectif ? On a l'impression que && doit faire moins de vérifications, il doit donc être beaucoup plus efficace.

Voici un exemple qui est une copie directe de && , l'adaptation ST_Intersects :

Vous trouverez ci-dessous un graphique simple de l'apparence de ces lignes. Je viens d'ajouter ceci tracé pour voir comment la boîte englobante fonctionne exactement pour les lignes. Pour mes besoins, les points sont toujours à l'intérieur de la boîte (alors que cet exemple de ligne ne reflète pas vraiment ce que j'essaie de faire mais bon pour l'illustration)

La question 1 est si && est significativement plus rapide que ST_Intersects lors de l'utilisation avec ST_MakeEnvelope (une limite rectangulaire), lors de la recherche de points à l'intérieur d'une boîte englobante rectangulaire.

La question 2 est également, est-ce que je comprends bien que lors de la vérification des points à l'intérieur d'une frontière rectangulaire, && fait exactement la même chose que ST_Intersects ?


Voir la vidéo: Espaces entre paragraphes et interligne Word