31 votes

Déterminer la coque non convexe de la collection de segments de ligne

J'ai un problème de géométrie computationnelle que je me sens devrait avoir une solution relativement simple, mais je ne peux pas tout à fait le comprendre.

J'ai besoin de déterminer la non-convexe contour d'une région définie par plusieurs segments de ligne.

Je suis au courant de diverses organisations non-enveloppe convexe des algorithmes (par exemple les alpha formes), mais je n'ai pas besoin pleinement algorithme général, comme les segments de ligne définir une unique solution dans la plupart des cas.


Comme @Jean-FrançoisCorbett l'a souligné, il y a des cas où il existe plusieurs solutions. J'ai clairement besoin de penser plus au sujet de ma définition.

Cependant, ce que je suis en train de faire est de le désosser et d'utiliser un format de fichier propriétaire, de sorte que je peux exécuter des analyses de base sur des données recueillies par moi-même et les autres. Le format de fichier est assez simple, mais la détermination de l'algorithme qu'ils utilisent pour définir la frontière est beaucoup plus difficile.

Mettre dans de nombreux cas limites qui aurait pour conséquence une non-solution unique provoque le logiciel en question soit de bloquer sans avertissement ou silencieux, ne parviennent pas à lire le fichier.

Par conséquent, lorsqu'il y a plusieurs solutions, soit en générant une des solutions acceptables, ou d'être en mesure de déterminer qu'il existe de multiples solutions serait acceptable.


Définition Du Problème:

Le polygone de contour ne doit jamais traverser l'un quelconque des segments et devrait être constitué de lignes joignant tous les segments terminaux. Tous les segments doivent se trouver entièrement à l'intérieur ou le long de la frontière du polygone. Pas de point de terminaison peut être utilisée plus d'une fois dans le plan (Ignorant la "fermeture" du polygone en ajoutant le premier point à la fin pour les bibliothèques logicielles qui nécessitent de polygones pour les fermer.).

Dans les cas où il existe plusieurs solutions qui répondent à ce critère, aucune de ces solutions serait acceptable. (Il serait agréable d'être en mesure de déterminer quand la solution n'est pas unique, mais ce n'est pas strictement nécessaire.)


Exemples:

Comme un exemple, j'ai quelque chose le long de ces lignes: Segments Defining the Area

Et je tiens à délimiter le domaine suivant: Desired Outline

Il devrait également travailler pour les non-intersection des segments. E. g.

enter image description hereenter image description here

Je pense (?) il y a une unique solution dans les deux cas, sous réserve des critères aperçu plus tôt. (Edit: Il n'y a pas une solution unique, en général, comme @Jean-FrançoisCorbett souligné. Cependant, je suis toujours intéressé à un algorithme qui permettrait de générer l'une des solutions acceptables.)

Des Cas De Test

Pour un cas de test, voici le code à générer les chiffres ci-dessus. Je suis à l'aide de python ici, mais la question est indépendant de la langue.

import matplotlib.pyplot as plt

def main():
    test1()
    test2()
    plt.show()

def test1():
    """Intersecting segments."""
    segments = [[(1, 1), (1, 3)],
                [(3.7, 1), (2, 4)],
                [(2, 0), (3.7, 3)],
                [(4, 0), (4, 4)],
                [(4.3, 1), (4.3, 3)],
                [(0, 2), (6, 3)]]

    desired_outline = [segments[0][0], segments[5][0], segments[0][1], 
                       segments[1][1], segments[2][1], segments[3][1],
                       segments[4][1], segments[5][1], segments[4][0],
                       segments[3][0], segments[1][0], segments[2][0],
                       segments[0][0]]

    plot(segments, desired_outline)

def test2():
    """Non-intersecting segments."""
    segments = [[(0, 1), (0, 3)],
                [(1, 0), (1, 4)],
                [(2, 1), (2, 3)],
                [(3, 0), (3, 4)]]

    desired_outline = [segments[0][0], segments[0][1], segments[1][1],
                       segments[2][1], segments[3][1], segments[3][0], 
                       segments[2][0], segments[1][0], segments[0][0]]

    plot(segments, desired_outline)


def plot(segments, desired_outline):
    fig, ax = plt.subplots()
    plot_segments(ax, segments)
    ax.set_title('Segments')

    fig, ax = plt.subplots()
    ax.fill(*zip(*desired_outline), facecolor='gray')
    plot_segments(ax, segments)
    ax.set_title('Desired Outline')

def plot_segments(ax, segments):
    for segment in segments:
        ax.plot(*zip(*segment), marker='o', linestyle='-')
    xmin, xmax, ymin, ymax = ax.axis()
    ax.axis([xmin - 0.5, xmax + 0.5, ymin - 0.5, ymax + 0.5])

if __name__ == '__main__':
    main()

Des idées?

Je commence à soupçonner que le logiciel dont les résultats que j'essaie de reproduire utilise une radiale de balayage de l'algorithme dans une sorte de "interne" du système de coordonnées (par exemple, Un système de coordonnées avec x-prime et y-prime à l'échelle et rotation le long des axes principaux définis par la propagation de points. Ce qui rend le problème plus "circulaire".) Cependant, ce qui produit des solutions où le contour coupe des segments de ligne dans de nombreux cas. Il est assez facile de le détecter et de force brute à partir de là, mais il y a certainement une meilleure façon?

17voto

Jean-François Corbett Points 16957
  1. Choisissez un coffre-fort point de départ. Peut être par exemple le point de terminaison avec le maximum de x.
  2. Mars le long du segment de ligne.
  3. Lors de la rencontre une intersection, toujours tourner à gauche et mars le long de ce nouveau segment.
  4. Lors de la rencontre d'un point de terminaison, de l'enregistrer. Goto 2.
  5. Arrêtez-vous lorsque vous avez rejoint votre point de départ. Votre liste d'enregistrement des points de terminaison, maintenant la liste ordonnée de sommets de votre concave de la coque.

NB: Ceci ne fonctionnera pas si il y a un "free-floating" périphériques segment de ligne qui ne croise aucun autre segment de ligne. Toutefois, vous indiquez que "les barres unique de définir une solution", ce qui exclut d'échec condition. (Périphériques segments de rendre possible deux solutions uniques.)

EDIT ... ou plutôt, éloignées des segments peut faire deux uniques solutions possibles, selon la mise en page exacte. La preuve: voici ci-Dessous un exemple où le segment jaune que j'ai ajouté deux solutions possibles (bleu et de gris horriblement dessinés à la main avec des lignes). Ont été le segment jaune orienté perpendiculairement à la façon dont il est établi maintenant, une seule solution serait possible. Semble que votre problème est mal défini.

enter image description here

EDIT en Fait cela peut également échouer si votre segment de la collection est "très concave", c'est à dire si il y a des points de terminaison niché dans reclus coins de votre tas de segments. Dans la figure ci-dessous, j'ai ajouté un segment noir. Mon algorithme illégalement se joindre à son extrémité à l'autre extrémité (pointillés gris ligne). Je vais quitter ma réponse dans le cas où d'autres sont enclins à développer.

EDIT après avoir donné ce peu plus de la pensée: Même dans le "très concave" cas, cette solution va certainement vous donner tous les points de votre concave de la coque dans le bon ordre, mais ils peuvent être intercalés avec des extra, inapproprié des points tels que le noir. Il peut donc y avoir trop de points.

La réponse est alors, bien sûr, de faire de l'élagage. Il serait assez compliqué élagage surtout si vous pouvez avoir de multiples consécutifs de "reclus points" comme le noir, donc je n'ai pas un algorithme intelligent dans l'esprit. Mais même la force aveugle et brutale pourrait être faisable. Chaque point peut être accepté ou rejeté (boolean), donc si vous avez N bien ordonné points candidats dans votre concave de la coque, puis il y a seulement 2^N possibilités pour vérifier. C'est une façon, de manière de moins en moins de possibilités que la force brute pour votre problème d'origine de permutations, ce qui aurait SUM of (n!/(n-k)!) for k=1:(n-1) possibilités (pardon pour mon notation). Donc, cet algorithme se rétrécit vers le bas de votre problème de manière significative.

Je pense que c'est le chemin à parcourir.

enter image description here

2voto

Scott Hunter Points 10356

Pas totalement étoffé, idée, mais de toute façon: Supposons que vous avez commencé w/ la circulaire de balayage de l'algorithme pour un convexe-hull (où vous triez, et ensuite, les points de par leur angle à partir d'un point central). Si tous les points à la fin dans cette coque, vous avez terminé. Si non, alors vous avez à "serrer" la coque afin d'inclure ces points. Chacun de ces points étaient à la fois des candidats pour l'enveloppe convexe, et l'ai enlevé parce qu'ils ont violé la convexness. Parfois (comme avec le haut violet point dans le premier exemple), nous pouvons simplement laisser dans. Où nous ne pouvons pas, parce que le nouveau segment de la coque traverse un segment (comme allant de bas en vert pour le fond violet dans le premier exemple, en supposant que le fond de l'aqua point eu de traitement avant le vert), la solution est un peu plus complexe (et de la partie je n'ai pas précisées, et est la partie la plus fait allusion dans la question de la dernière modification).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X