Come faccio a determinare se un poligono ne contiene completamente un altro?


9

Ho 2 poligoni. Conosco le coordinate del vertice di entrambi i poligoni. Qual è il modo migliore per verificare se uno è completamente dentro l'altro? Ad esempio, l'algoritmo dovrebbe riconoscere solo il trapezio nero di seguito come contenuto:

poligoni di esempio


Non posso dare una risposta dettagliata in questo momento (potrei farlo più tardi), ma dovresti dare un'occhiata a un'implementazione per il teorema degli assi di separazione per il rilevamento delle collisioni. L'algoritmo può essere leggermente modificato per verificare facilmente ciò che si desidera. ad esempio codezealot.org/archives/55
TravisG,

1
Non hai esattamente capito cosa capisci di un poligono all'interno del poligono. Che cosa succede se tutti i punti del poligono più piccolo si trovano in quello più grande, ma ognuno di essi ha un lato su una linea, sono l'uno nell'altro? i47.tinypic.com/4i0sgg.jpg
speedyGonzales

@speedyGonzales, questo è anche chiamato dentro.
user960567

Risposte:


5

Esistono tonnellate di frammenti di origine per un metodo che esegue un test per " punto all'interno del poligono ". Il principio deriva dal teorema della curva della Giordania per i poligoni ( http://www-cgrl.cs.mcgill.ca/~godfried/teaching/cg-projects/97/Octavian/compgeom.html ).

Il modo ingenuo sarebbe: avendo quel metodo, chiamalo PointInsidePolygon(Point p, Polygon poly):

  bool isInside = true;
  for each (Point p in innerPoly)
  {
    if (!PointInsidePolygon(p, outerPoly))
    {
      isInside = false; // at least one point of the innerPoly is outside the outerPoly
      break;
    }
  }
  if (!isInside) return false;
  // COMPULSORY EDGE INTERSECTION CHECK
  for each (innerEdge in innerPoly)
    for each (outerEdge in outerPoly)
    {
      if (EdgesIntersect(innerEdge, outerEdge))
      {
        isInside = false;
        break;
      }
    }

  return isInside;

Teoricamente, non dovrebbe mancare nessuno scenario per i tuoi poligoni, ma non è la soluzione ottimale.

Osservazioni sul caso "Edge"

  • PointInsidePolygon(..) deve restituire true se il punto si trova sul bordo del poligono (o si trova su un bordo o è un vertice)

  • EdgesIntersect(..)deve restituire false se innerEdgeè un sottoinsieme (dal punto di vista geometrico) di outerEdge. In questo caso, i bordi ovviamente si intersecano, ma ai fini dell'algoritmo, dobbiamo indicare che l'intersezione non sta infrangendo la semantica dietro la isInsidevariabile

Remakrs generali :

  • senza i controlli di intersezione tra spigolo e spigolo, come sottolineato nei commenti, l'approccio potrebbe restituire falsi positivi per alcuni poligoni concavi (ad esempio un quadratino a V e un rettangolo - il rettangolo potrebbe avere tutti i suoi vertici all'interno della forma a V, ma intersecarlo , avendo quindi almeno alcune aree all'esterno).

  • dopo che uno controlla che almeno uno dei vertici del poligono interno sia all'interno di quello esterno, e se non ci sono bordi intersecanti, significa che la condizione desiderata è soddisfatta.


1
Ciò restituirà falsi positivi quando il poligono esterno è concavo.
Sam Hocevar,

2
Abbastanza divertente, mentre quelli di teodron e knight666 si sbagliano individualmente, se combinati, dovrebbero dare una risposta giusta. Se tutti i punti di un poligono si trovano all'interno di un altro e se le loro linee non si intersecano, il primo poli è completamente all'interno dell'altro.
Hackworth,

È vero, restituisce falsi positivi, deve tenere conto anche delle intersezioni dei bordi.
teodron,

Questa sembra essere la risposta corretta. Penso che non sia necessario controllare la condizione del secondo loop.
user960567

Questo non funziona per le intersezioni degli endpoint o se i bordi si sovrappongono.
Brandon Kohn

2

Prova a fare un'intersezione di linea con ogni linea rossa. In pseudocodice:

// loop over polygons
for (int i = 0; i < m_PolygonCount; i++)
{
    bool contained = false;

    for (int j = 0; j < m_Polygon[i].GetLineCount(); j++)
    {
        for (int k = 0; k < m_PolygonContainer.GetLineCount(); k++)
        {
            // if a line of the container polygon intersects with a line of the polygon
            // we know it's not fully contained
            if (m_PolygonContainer.GetLine(k).Intersects(m_Polygon[i].GetLine(j)))
            {
                contained = false;
                break;
            }
        }

        // it only takes one intersection to invalidate the polygon
        if (!contained) { break; }
    }

    // here contained is true if the polygon is fully inside the container
    // and false if it's not
}

Tuttavia, come puoi vedere, questa soluzione diventerà più lenta man mano che aggiungi più poligoni da controllare. Una soluzione diversa potrebbe essere:

  • Renderizza il poligono contenitore in un buffer di pixel con un colore bianco.
  • Rendering di un poligono figlio in un buffer di pixel diverso con un colore bianco.
  • Maschera il buffer contenitore sopra il buffer poligono con una maschera XOR.
  • Conta il numero di pixel bianchi; se è maggiore di 0, il poligono figlio non è completamente contenuto dal contenitore.

Questa soluzione è molto veloce, ma dipende dalla tua implementazione (e da cosa vuoi fare con il risultato del tuo controllo) quale soluzione funziona meglio per te.


1
Le intersezioni di linea non saranno sufficienti per individuare poligoni completamente contenuti.
Kylotan,

1
Domanda: se i poligoni sono completamente disgiunti, i bordi non si intersecano. Funzionerà in questo caso? Il secondo approccio basato sulla grafica dovrebbe funzionare davvero!
teodron,
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.