📜  动态凸包|向现有凸包添加点

📅  最后修改于: 2021-04-28 14:03:53             🧑  作者: Mango

给定凸包,我们需要在凸包中添加给定数量的点,并在每次添加点后打印凸包。添加每个点后,这些点应按逆时针顺序排列。
例子:

Input : 
Convex Hull : (0, 0), (3, -1), (4, 5), (-1, 4)
Point to add : (100, 100)

Output :
New convex hull : (-1, 4) (0, 0) (3, -1) (100, 100)

我们首先检查该点是否在给定的凸包内。如果是,则无需执行任何操作,我们将直接返回给定的凸包。如果该点在凸包之外,我们将找到上下切线,然后将该点与给定的凸包合并以找到新的凸包,如图所示。

point_to_hull2

红色轮廓线显示了合并该点和给定凸包后的新凸包。
要找到上切线,我们首先在船体上选择一个最接近给定点的点。然后,当连接凸包上的点和给定点的线穿过凸包时,我们逆时针移动,直到得到切线。

point_to_hull

该图显示了凸包上的点的移动,以找到上切线。
注意:这里假定初始凸包的输入是逆时针顺序的,否则我们必须首先以逆时针顺序对其进行排序,然后应用以下代码。

代码:

CPP
// C++ program to add given a point p to a given
// convext hull. The program assumes that the
// point of given convext hull are in anti-clockwise
// order.
#include
using namespace std;
 
// checks whether the point crosses the convex hull
// or not
int orientation(pair a, pair b,
                pair c)
{
    int res = (b.second-a.second)*(c.first-b.first) -
              (c.second-b.second)*(b.first-a.first);
 
    if (res == 0)
        return 0;
    if (res > 0)
        return 1;
    return -1;
}
 
// Returns the square of distance between two input points
int sqDist(pair p1, pair p2)
{
    return (p1.first-p2.first)*(p1.first-p2.first) +
           (p1.second-p2.second)*(p1.second-p2.second);
}
 
// Checks whether the point is inside the convex hull or not
bool inside(vector> a, pair p)
{
    // Initialize the centroid of the convex hull
    pair mid = {0, 0};
 
    int n = a.size();
 
    // Multiplying with n to avoid floating point
    // arithmetic.
    p.first *= n;
    p.second *= n;
    for (int i=0; i> &a, pair p)
{
    // If point is inside p
    if (inside(a, p))
        return;
   
    // point having minimum distance from the point p
    int ind = 0;
    int n = a.size();
    for (int i=1; i=0)
        up = (up + 1) % n;
 
    // Find the lower tangent
    int low = ind;
    while (orientation(p, a[low], a[(n+low-1)%n])<=0)
        low = (n+low - 1) % n;
 
    // Initialize result
    vector>ret;
 
    // making the final hull by traversing points
    // from up to low of given convex hull.
    int curr = up;
    ret.push_back(a[curr]);
    while (curr != low)
    {
        curr = (curr+1)%n;
        ret.push_back(a[curr]);
    }
 
    // Modify the original vector
    ret.push_back(p);
    a.clear();
    for (int i=0; i > a;
    a.push_back({0, 0});
    a.push_back({3, -1});
    a.push_back({4, 5});
    a.push_back({-1, 4});
    int n = a.size();
 
    pair p = {100, 100};
    addPoint(a, p);
 
    // Print the modified Convex Hull
    for (auto e : a)
        cout << "(" << e.first << ", "
              << e.second << ") ";
 
    return 0;
}


Java
// Java program to add given a point p to a given
// convext hull. The program assumes that the
// point of given convext hull are in anti-clockwise
// order.
 
import java.io.*;
import java.util.*;
class GFG
{
 
  // checks whether the point crosses the convex hull
  // or not
  static int orientation(ArrayList a,
                         ArrayList b,
                         ArrayList c)
  {
    int res = (b.get(1) - a.get(1)) * (c.get(0) - b.get(0)) -
      (c.get(1) - b.get(1)) * (b.get(0)-a.get(0));
    if (res == 0)
      return 0;
    if (res > 0)
      return 1;
    return -1;
  }
 
  // Returns the square of distance between two input points
  static int sqDist(ArrayListp1, ArrayListp2)
  {
    return (p1.get(0) - p2.get(0)) * (p1.get(0) - p2.get(0)) +
      (p1.get(1) - p2.get(1)) * (p1.get(1) - p2.get(1));
  }
 
  // Checks whether the point is inside the convex hull or not
  static boolean inside(ArrayList> A,ArrayListp)
  {
 
    // Initialize the centroid of the convex hull
    ArrayList mid = new ArrayList(Arrays.asList(0,0));
 
    int n = A.size();
 
 
    for (int i = 0; i < n; i++)
    {
      mid.set(0,mid.get(0) + A.get(i).get(0));
      mid.set(1,mid.get(1) + A.get(i).get(1));
 
    }
 
    // if the mid and the given point lies always
    // on the same side w.r.t every edge of the
    // convex hull, then the point lies inside
    // the convex hull
    for (int i = 0, j; i < n; i++)
    {
      j = (i + 1) % n;
      int x1 = A.get(i).get(0)*n, x2 = A.get(j).get(0)*n;
      int y1 = A.get(i).get(1)*n, y2 = A.get(j).get(1)*n;
      int a1 = y1 - y2;
      int b1 = x2 - x1;
      int c1 = x1 * y2 - y1 * x2;
      int for_mid = a1 * mid.get(0) + b1 * mid.get(1) + c1;
      int for_p = a1 * p.get(0) * n + b1 * p.get(1) * n + c1;
      if (for_mid*for_p < 0)
        return false;
    }
    return true;
  }
 
  // Adds a point p to given convex hull a[]
  static void addPoint(ArrayList> a,ArrayList p)
  {
 
    // If point is inside p
    if (inside(a, p))
      return;
 
    // point having minimum distance from the point p
    int ind = 0;
    int n = a.size();
    for (int i = 1; i < n; i++)
    {
      if (sqDist(p, a.get(i)) < sqDist(p, a.get(ind)))
      {
        ind = i;
      }
    }
 
    // Find the upper tangent
    int up = ind;
    while (orientation(p, a.get(up), a.get((up+1)%n))>=0)
      up = (up + 1) % n;
 
    // Find the lower tangent
    int low = ind;
    while (orientation(p, a.get(low), a.get((n+low-1)%n))<=0)
      low = (n+low - 1) % n;
 
    // Initialize result
    ArrayList> ret = new ArrayList>();
 
    // making the final hull by traversing points
    // from up to low of given convex hull.
    int curr = up;
    ret.add(a.get(curr));
 
    while (curr != low)
    {
      curr = (curr + 1) % n;
      ret.add(a.get(curr));
    }
 
    // Modify the original vector
 
    ret.add(p);
    a.clear();
    for (int i = 0; i < ret.size(); i++)
    {
      a.add(ret.get(i));
    }
  }
 
  // Driver code
  public static void main (String[] args)
  {
 
    // the set of points in the convex hull
    ArrayList> a = new ArrayList>();
 
    a.add(new ArrayList(Arrays.asList(0, 0)));
    a.add(new ArrayList(Arrays.asList(3, -1)));
    a.add(new ArrayList(Arrays.asList(4, 5)));
    a.add(new ArrayList(Arrays.asList(-1, 4)));
 
    int n = a.size();
 
    ArrayList p = new ArrayList(Arrays.asList(100,100));
 
    addPoint(a, p);
    // Print the modified Convex Hull
    for(ArrayList e:a )
    {
      System.out.print("(" + e.get(0) + ", " + e.get(1) + ") ");
    }
  }
}
 
// This code is contributed by rag2127


Python3
# Python 3 program to add given a point p to a given
# convext hull. The program assumes that the
# point of given convext hull are in anti-clockwise
# order.
import copy
 
# checks whether the point crosses the convex hull
# or not
def orientation(a, b, c):
 
    res = ((b[1] - a[1]) * (c[0] - b[0]) -
              (c[1] - b[1]) * (b[0] - a[0]))
 
    if (res == 0):
        return 0;
    if (res > 0):
        return 1;
    return -1;
 
# Returns the square of distance between two input points
def sqDist(p1, p2):
 
    return ((p1[0] - p2[0]) * (p1[0] - p2[0]) +
           (p1[1] - p2[1]) * (p1[1] - p2[1]));
 
# Checks whether the point is inside the convex hull or not
def inside( a, p ):
 
    # Initialize the centroid of the convex hull
    mid = [0, 0]
 
    n = len(a)
 
    # Multiplying with n to avoid floating point
    # arithmetic.
    p[0] *= n;
    p[1] *= n;
    for i in range(n):
       
        mid[0] += a[i][0];
        mid[1] += a[i][1];
        a[i][0] *= n;
        a[i][1] *= n;
     
    # if the mid and the given point lies always
    # on the same side w.r.t every edge of the
    # convex hull, then the point lies inside
    # the convex hull
    for i in range( n ):
     
        j = (i + 1) % n;
        x1 = a[i][0]
        x2 = a[j][0]
        y1 = a[i][1]
        y2 = a[j][1]
        a1 = y1 - y2;
        b1 = x2 - x1;
        c1 = x1 * y2 - y1 * x2;
        for_mid = a1 * mid[0] + b1 * mid[1] + c1;
        for_p = a1 * p[0] + b1*p[1]+c1;
        if (for_mid*for_p < 0):
            return False;
    
    return True;
 
# Adds a point p to given convex hull a[]
def addPoint( a, p):
 
    # If point is inside p
    arr= copy.deepcopy(a)
    prr =p.copy()
     
    if (inside(arr, prr)):
        return;
   
    # point having minimum distance from the point p
    ind = 0;
    n = len(a)
    for i in range(1, n):
        if (sqDist(p, a[i]) < sqDist(p, a[ind])):
            ind = i
 
    # Find the upper tangent
    up = ind;
    while (orientation(p, a[up], a[(up + 1) % n]) >= 0):
        up = (up + 1) % n;
 
    # Find the lower tangent
    low = ind;
    while (orientation(p, a[low], a[(n + low - 1) % n]) <= 0):
        low = (n + low - 1) % n
 
    # Initialize result
    ret = []
 
    # making the final hull by traversing points
    # from up to low of given convex hull.
    curr = up;
    ret.append(a[curr]);
    while (curr != low):
        curr = (curr + 1) % n;
        ret.append(a[curr]);
 
    # Modify the original vector
    ret.append(p);
    a.clear();
    for i in range(len(ret)):
        a.append(ret[i]);
 
# Driver code
if __name__ == "__main__":
   
    # the set of points in the convex hull
    a = []
    a.append([0, 0]);
    a.append([3, -1]);
    a.append([4, 5]);
    a.append([-1, 4]);
    n = len(a)
 
    p = [100, 100]
    addPoint(a, p);
 
    # Print the modified Convex Hull
    for e in a :
        print("(" , e[0], ", ",
              e[1] , ") ",end=" ")
 
# This code is contributed by chitranayal


C#
// C# program to add given a point p to a given
// convext hull. The program assumes that the
// point of given convext hull are in anti-clockwise
// order.
 
using System;
using System.Collections.Generic;
 
public class GFG{
 
  // checks whether the point crosses the convex hull
  // or not
  static int orientation(List a,List b,List c)
  {
    int res=(b[1]-a[1]) * (c[0]-b[0]) - (c[1]-b[1]) * (b[0]-a[0]);
    if (res == 0)
      return 0;
    if (res > 0)
      return 1;
    return -1;
  }
  // Returns the square of distance between two input points
  static int sqDist(Listp1, Listp2)
  {
    return (p1[0] - p2[0]) * (p1[0] - p2[0]) +
      (p1[1] - p2[1]) * (p1[1] - p2[1]);
  }
 
  // Checks whether the point is inside the convex hull or not
  static bool inside(List> A,Listp)
  {
 
    // Initialize the centroid of the convex hull
    List mid = new List(){0,0};
 
    int n = A.Count;
 
 
    for (int i = 0; i < n; i++)
    {
      mid[0]+=A[i][0];
      mid[1]+=A[i][1];
 
    }  
 
    // if the mid and the given point lies always
    // on the same side w.r.t every edge of the
    // convex hull, then the point lies inside
    // the convex hull
    for (int i = 0, j; i < n; i++)
    {
      j = (i + 1) % n;
      int x1 = A[i][0]*n, x2 = A[j][0]*n;
      int y1 = A[i][1]*n, y2 = A[j][1]*n;
      int a1 = y1 - y2;
      int b1 = x2 - x1;
      int c1 = x1 * y2 - y1 * x2;
      int for_mid = a1 * mid[0] + b1 * mid[1] + c1;
      int for_p = a1 * p[0] * n + b1 * p[1] * n + c1;
      if (for_mid*for_p < 0)
        return false;
    }
    return true;
  }
 
  // Adds a point p to given convex hull a[]
  static void addPoint(List> a,List p)
  {
 
    // If point is inside p
    if (inside(a, p))
      return;
 
    // point having minimum distance from the point p
    int ind = 0;
    int n = a.Count;
    for (int i = 1; i < n; i++)
    {
      if (sqDist(p, a[i]) < sqDist(p, a[ind]))
      {
        ind = i;
      }
    }
 
    // Find the upper tangent
    int up = ind;
    while (orientation(p, a[up], a[(up+1)%n])>=0)
      up = (up + 1) % n;
 
    // Find the lower tangent
    int low = ind;
    while (orientation(p, a[low], a[(n+low-1)%n])<=0)
      low = (n+low - 1) % n;
 
    // Initialize result
    List> ret = new List>();
 
    // making the final hull by traversing points
    // from up to low of given convex hull.
    int curr = up;
    ret.Add(a[curr]);
 
    while (curr != low)
    {
      curr = (curr + 1) % n;
      ret.Add(a[curr]);
    }
 
    // Modify the original vector
 
    ret.Add(p);
    a.Clear();
    for (int i = 0; i < ret.Count; i++)
    {
      a.Add(ret[i]);
    }
  }
 
  // Driver code
 
 
  static public void Main (){
    // the set of points in the convex hull
    List> a = new List>();
 
    a.Add(new List(){0,0});
    a.Add(new List(){3,-1});
    a.Add(new List(){4,5});
    a.Add(new List(){-1,4});
 
    int n=a.Count;
    List p = new List(){100,100};
    addPoint(a, p);
    // Print the modified Convex Hull
    foreach(List e in a)
    {
      Console.Write("(" + e[0] + ", " + e[1] + ") ");
    }
 
  }
}
 
// This code is contributed by avanitrachhadiya2155


输出:

(-1, 4) (0, 0) (3, -1) (100, 100)