Casco convexo | Conjunto 1 (Algoritmo de Jarvis o Wrapping)

Dado un conjunto de puntos en el plano. la envolvente convexa del conjunto es el polígono convexo más pequeño que contiene todos los puntos del mismo.
 

Recomendamos encarecidamente ver la siguiente publicación primero. 
¿Cómo verificar si dos segmentos de línea dados se cruzan?
La idea del Algoritmo de Jarvis es simple, comenzamos desde el punto más a la izquierda (o el punto con el valor mínimo de la coordenada x) y seguimos envolviendo los puntos en dirección contraria a las manecillas del reloj. 

La gran pregunta es, dado un punto p como punto actual, ¿cómo encontrar el siguiente punto en la salida? 

La idea es usar la orientación() aquí. El siguiente punto se selecciona como el punto que supera a todos los demás puntos en sentido antihorario, es decir, el siguiente punto es q si para cualquier otro punto r, tenemos «orientación (p, q, r) = antihorario». 

 Algoritmo:
Paso 1) Inicialice p como el punto más a la izquierda. 
Paso 2) Siga mientras no volvamos al primer punto (o más a la izquierda). 
            2.1) El siguiente punto q es el punto, tal que el triplete (p, q, r) es en sentido antihorario para cualquier otro punto r. 

                    Para encontrar esto, simplemente inicializamos q como el siguiente punto, luego recorremos todos los puntos. 

                    Para cualquier punto i, si i es más en sentido contrario a las agujas del reloj, es decir, la orientación (p, i, q) es en sentido contrario a las agujas del reloj, entonces actualizamos q como i. 

                    Nuestro valor final de q va a ser el punto más contrario a las agujas del reloj. 
           2.2) next[p] = q (Almacenar q como siguiente de p en el casco convexo de salida). 
           2.3) p = q (Establezca p como q para la próxima iteración).
 

A continuación se muestra la implementación del algoritmo anterior. 
 

C++

// A C++ program to find convex hull of a set of points. Refer
// https://www.geeksforgeeks.org/orientation-3-ordered-points/
// for explanation of orientation()
#include <bits/stdc++.h>
using namespace std;
 
struct Point
{
    int x, y;
};
 
// To find orientation of ordered triplet (p, q, r).
// The function returns following values
// 0 --> p, q and r are collinear
// 1 --> Clockwise
// 2 --> Counterclockwise
int orientation(Point p, Point q, Point r)
{
    int val = (q.y - p.y) * (r.x - q.x) -
              (q.x - p.x) * (r.y - q.y);
 
    if (val == 0) return 0;  // collinear
    return (val > 0)? 1: 2; // clock or counterclock wise
}
 
// Prints convex hull of a set of n points.
void convexHull(Point points[], int n)
{
    // There must be at least 3 points
    if (n < 3) return;
 
    // Initialize Result
    vector<Point> hull;
 
    // Find the leftmost point
    int l = 0;
    for (int i = 1; i < n; i++)
        if (points[i].x < points[l].x)
            l = i;
 
    // Start from leftmost point, keep moving counterclockwise
    // until reach the start point again.  This loop runs O(h)
    // times where h is number of points in result or output.
    int p = l, q;
    do
    {
        // Add current point to result
        hull.push_back(points[p]);
 
        // Search for a point 'q' such that orientation(p, q,
        // x) is counterclockwise for all points 'x'. The idea
        // is to keep track of last visited most counterclock-
        // wise point in q. If any point 'i' is more counterclock-
        // wise than q, then update q.
        q = (p+1)%n;
        for (int i = 0; i < n; i++)
        {
           // If i is more counterclockwise than current q, then
           // update q
           if (orientation(points[p], points[i], points[q]) == 2)
               q = i;
        }
 
        // Now q is the most counterclockwise with respect to p
        // Set p as q for next iteration, so that q is added to
        // result 'hull'
        p = q;
 
    } while (p != l);  // While we don't come to first point
 
    // Print Result
    for (int i = 0; i < hull.size(); i++)
        cout << "(" << hull[i].x << ", "
              << hull[i].y << ")\n";
}
 
// Driver program to test above functions
int main()
{
    Point points[] = {{0, 3}, {2, 2}, {1, 1}, {2, 1},
                      {3, 0}, {0, 0}, {3, 3}};
    int n = sizeof(points)/sizeof(points[0]);
    convexHull(points, n);
    return 0;
}

Java

// Java program to find convex hull of a set of points. Refer
// https://www.geeksforgeeks.org/orientation-3-ordered-points/
// for explanation of orientation()
import java.util.*;
 
class Point
{
    int x, y;
    Point(int x, int y){
        this.x=x;
        this.y=y;
    }
}
 
class GFG {
     
    // To find orientation of ordered triplet (p, q, r).
    // The function returns following values
    // 0 --> p, q and r are collinear
    // 1 --> Clockwise
    // 2 --> Counterclockwise
    public static int orientation(Point p, Point q, Point r)
    {
        int val = (q.y - p.y) * (r.x - q.x) -
                  (q.x - p.x) * (r.y - q.y);
      
        if (val == 0) return 0;  // collinear
        return (val > 0)? 1: 2; // clock or counterclock wise
    }
     
    // Prints convex hull of a set of n points.
    public static void convexHull(Point points[], int n)
    {
        // There must be at least 3 points
        if (n < 3) return;
      
        // Initialize Result
        Vector<Point> hull = new Vector<Point>();
      
        // Find the leftmost point
        int l = 0;
        for (int i = 1; i < n; i++)
            if (points[i].x < points[l].x)
                l = i;
      
        // Start from leftmost point, keep moving
        // counterclockwise until reach the start point
        // again. This loop runs O(h) times where h is
        // number of points in result or output.
        int p = l, q;
        do
        {
            // Add current point to result
            hull.add(points[p]);
      
            // Search for a point 'q' such that
            // orientation(p, q, x) is counterclockwise
            // for all points 'x'. The idea is to keep
            // track of last visited most counterclock-
            // wise point in q. If any point 'i' is more
            // counterclock-wise than q, then update q.
            q = (p + 1) % n;
             
            for (int i = 0; i < n; i++)
            {
               // If i is more counterclockwise than
               // current q, then update q
               if (orientation(points[p], points[i], points[q])
                                                   == 2)
                   q = i;
            }
      
            // Now q is the most counterclockwise with
            // respect to p. Set p as q for next iteration,
            // so that q is added to result 'hull'
            p = q;
      
        } while (p != l);  // While we don't come to first
                           // point
      
        // Print Result
        for (Point temp : hull)
            System.out.println("(" + temp.x + ", " +
                                temp.y + ")");
    }
     
    /* Driver program to test above function */
    public static void main(String[] args)
    {
 
        Point points[] = new Point[7];
        points[0]=new Point(0, 3);
        points[1]=new Point(2, 3);
        points[2]=new Point(1, 1);
        points[3]=new Point(2, 1);
        points[4]=new Point(3, 0);
        points[5]=new Point(0, 0);
        points[6]=new Point(3, 3);
         
        int n = points.length;
        convexHull(points, n);
        
    }
}
   
// This code is contributed by Arnav Kr. Mandal.

Python3

# Python3 program to find convex hull of a set of points. Refer
# https://www.geeksforgeeks.org/orientation-3-ordered-points/
# for explanation of orientation()
 
# point class with x, y as point
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
 
def Left_index(points):
     
    '''
    Finding the left most point
    '''
    minn = 0
    for i in range(1,len(points)):
        if points[i].x < points[minn].x:
            minn = i
        elif points[i].x == points[minn].x:
            if points[i].y > points[minn].y:
                minn = i
    return minn
 
def orientation(p, q, r):
    '''
    To find orientation of ordered triplet (p, q, r).
    The function returns following values
    0 --> p, q and r are collinear
    1 --> Clockwise
    2 --> Counterclockwise
    '''
    val = (q.y - p.y) * (r.x - q.x) - \
          (q.x - p.x) * (r.y - q.y)
 
    if val == 0:
        return 0
    elif val > 0:
        return 1
    else:
        return 2
 
def convexHull(points, n):
     
    # There must be at least 3 points
    if n < 3:
        return
 
    # Find the leftmost point
    l = Left_index(points)
 
    hull = []
     
    '''
    Start from leftmost point, keep moving counterclockwise
    until reach the start point again. This loop runs O(h)
    times where h is number of points in result or output.
    '''
    p = l
    q = 0
    while(True):
         
        # Add current point to result
        hull.append(p)
 
        '''
        Search for a point 'q' such that orientation(p, q,
        x) is counterclockwise for all points 'x'. The idea
        is to keep track of last visited most counterclock-
        wise point in q. If any point 'i' is more counterclock-
        wise than q, then update q.
        '''
        q = (p + 1) % n
 
        for i in range(n):
             
            # If i is more counterclockwise
            # than current q, then update q
            if(orientation(points[p],
                           points[i], points[q]) == 2):
                q = i
 
        '''
        Now q is the most counterclockwise with respect to p
        Set p as q for next iteration, so that q is added to
        result 'hull'
        '''
        p = q
 
        # While we don't come to first point
        if(p == l):
            break
 
    # Print Result
    for each in hull:
        print(points[each].x, points[each].y)
 
# Driver Code
points = []
points.append(Point(0, 3))
points.append(Point(2, 2))
points.append(Point(1, 1))
points.append(Point(2, 1))
points.append(Point(3, 0))
points.append(Point(0, 0))
points.append(Point(3, 3))
 
convexHull(points, len(points))
 
# This code is contributed by
# Akarsh Somani, IIIT Kalyani

C#

// C# program to find convex hull of a set of points. Refer
// https://www.geeksforgeeks.org/orientation-3-ordered-points/
// for explanation of orientation()
using System;
using System.Collections.Generic;
     
public class Point
{
    public int x, y;
    public Point(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
}
 
public class GFG
{
     
    // To find orientation of ordered triplet (p, q, r).
    // The function returns following values
    // 0 --> p, q and r are collinear
    // 1 --> Clockwise
    // 2 --> Counterclockwise
    public static int orientation(Point p, Point q, Point r)
    {
        int val = (q.y - p.y) * (r.x - q.x) -
                (q.x - p.x) * (r.y - q.y);
     
        if (val == 0) return 0; // collinear
        return (val > 0)? 1: 2; // clock or counterclock wise
    }
     
    // Prints convex hull of a set of n points.
    public static void convexHull(Point []points, int n)
    {
        // There must be at least 3 points
        if (n < 3) return;
     
        // Initialize Result
        List<Point> hull = new List<Point>();
     
        // Find the leftmost point
        int l = 0;
        for (int i = 1; i < n; i++)
            if (points[i].x < points[l].x)
                l = i;
     
        // Start from leftmost point, keep moving
        // counterclockwise until reach the start point
        // again. This loop runs O(h) times where h is
        // number of points in result or output.
        int p = l, q;
        do
        {
            // Add current point to result
            hull.Add(points[p]);
     
            // Search for a point 'q' such that
            // orientation(p, q, x) is counterclockwise
            // for all points 'x'. The idea is to keep
            // track of last visited most counterclock-
            // wise point in q. If any point 'i' is more
            // counterclock-wise than q, then update q.
            q = (p + 1) % n;
             
            for (int i = 0; i < n; i++)
            {
            // If i is more counterclockwise than
            // current q, then update q
            if (orientation(points[p], points[i], points[q])
                                                == 2)
                q = i;
            }
     
            // Now q is the most counterclockwise with
            // respect to p. Set p as q for next iteration,
            // so that q is added to result 'hull'
            p = q;
     
        } while (p != l); // While we don't come to first
                        // point
     
        // Print Result
        foreach (Point temp in hull)
            Console.WriteLine("(" + temp.x + ", " +
                                temp.y + ")");
    }
     
    /* Driver code */
    public static void Main(String[] args)
    {
 
        Point []points = new Point[7];
        points[0]=new Point(0, 3);
        points[1]=new Point(2, 3);
        points[2]=new Point(1, 1);
        points[3]=new Point(2, 1);
        points[4]=new Point(3, 0);
        points[5]=new Point(0, 0);
        points[6]=new Point(3, 3);
         
        int n = points.Length;
        convexHull(points, n);
         
    }
}
 
// This code is contributed by Princi Singh

Javascript

<script>
// Javascript program to find convex hull of a set of points. Refer
// https://www.geeksforgeeks.org/orientation-3-ordered-points/
// for explanation of orientation()
 
class Point
{
    constructor(x, y)
    {
        this.x = x;
        this.y = y;
    }
}
 
// To find orientation of ordered triplet (p, q, r).
    // The function returns following values
    // 0 --> p, q and r are collinear
    // 1 --> Clockwise
    // 2 --> Counterclockwise
function orientation(p, q, r)
{
    let val = (q.y - p.y) * (r.x - q.x) -
                  (q.x - p.x) * (r.y - q.y);
        
        if (val == 0) return 0;  // collinear
        return (val > 0)? 1: 2; // clock or counterclock wise
}
 
// Prints convex hull of a set of n points.
function convexHull(points, n)
{
    // There must be at least 3 points
        if (n < 3) return;
        
        // Initialize Result
        let hull = [];
        
        // Find the leftmost point
        let l = 0;
        for (let i = 1; i < n; i++)
            if (points[i].x < points[l].x)
                l = i;
        
        // Start from leftmost point, keep moving
        // counterclockwise until reach the start point
        // again. This loop runs O(h) times where h is
        // number of points in result or output.
        let p = l, q;
        do
        {
         
            // Add current point to result
            hull.push(points[p]);
        
            // Search for a point 'q' such that
            // orientation(p, q, x) is counterclockwise
            // for all points 'x'. The idea is to keep
            // track of last visited most counterclock-
            // wise point in q. If any point 'i' is more
            // counterclock-wise than q, then update q.
            q = (p + 1) % n;
               
            for (let i = 0; i < n; i++)
            {
               // If i is more counterclockwise than
               // current q, then update q
               if (orientation(points[p], points[i], points[q])
                                                   == 2)
                   q = i;
            }
        
            // Now q is the most counterclockwise with
            // respect to p. Set p as q for next iteration,
            // so that q is added to result 'hull'
            p = q;
        
        } while (p != l);  // While we don't come to first
                           // point
        
        // Print Result
        for (let temp of hull.values())
            document.write("(" + temp.x + ", " +
                                temp.y + ")<br>");
}
 
/* Driver program to test above function */
let points = new Array(7);
points[0] = new Point(0, 3);
points[1] = new Point(2, 3);
points[2] = new Point(1, 1);
points[3] = new Point(2, 1);
points[4] = new Point(3, 0);
points[5] = new Point(0, 0);
points[6] = new Point(3, 3);
 
let n = points.length;
convexHull(points, n);
 
// This code is contributed by avanitrachhadiya2155
</script>

Salida: La salida son puntos del casco convexo. 
 

(0, 3)
(0, 0)
(3, 0)
(3, 3)

Complejidad de tiempo:  O(m * n) , donde n es el número de puntos de entrada y m es el número de puntos de salida o casco (m <= n). Para cada punto del casco, examinamos todos los demás puntos para determinar el siguiente punto.

Peor caso, Complejidad temporal: O(n 2 ) . El peor caso ocurre cuando todos los puntos están en el casco (m = n).

Espacio auxiliar: O(n)
Set 2- Casco convexo (Graham Scan) 
Nota : El código anterior puede producir resultados diferentes para diferentes órdenes de entradas, cuando hay puntos colineales en el casco convexo. Por ejemplo, produce una salida como (0, 3) (0, 0) (3, 0) (3, 3) para la entrada (0, 3), (0, 0), (0, 1), (3, 0), (3, 3) y salida como (0, 3) (0, 1) (0, 0) (3, 0) (3, 3) para entrada como (0, 3), (0, 1) , (0, 0), (3, 0), (3, 3). Generalmente necesitamos el siguiente punto más lejano en el caso de colineales, podemos obtener el resultado deseado en el caso de puntos colineales agregando una condición if más. Consulte este código modificado.
Fuentes:  
http://www.cs.uiuc.edu/~jeffe/teaching/373/notes/x05-convexhull.pdf  
http://www.dcs.gla.ac.uk/~pat/52233/slides/Hull1x1 .pdf
Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.
 

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *