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.