Given two convex polygons, we aim to identify the lower and upper tangents connecting them.
As shown in the figure below, TRL and TLR represent the upper and lower tangents, respectively.
Examples:
Input: First Polygon : [[2, 2], [3, 3], [5, 2], [4, 0], [3, 1]] Second Polygon : [[-1, 0], [0, 1], [1, 0], [0, -2]]. Output: Upper Tangent - line joining (0,1) and (3,3) Lower Tangent - line joining (0,-2) and (4,0) Explanation: The image clearly shows the structure and the tangents connecting the two polygons
Approach:
To find the upper tangent, we begin by selecting two points: the rightmost point of polygon a and the leftmost point of polygon b. The line joining these two points is labeled as Line 1. Since this line passes through polygon b (i.e., it is not completely above it), we move to the next point in an anti-clockwise direction on b, forming Line2. This line is now above polygon b, which is good. However, it crosses polygon a, so we move to the next point on a in a clockwise direction, creating Line 3. Line 3 still crosses polygon a, prompting another move to Line 4. Line 4, however, crosses polygon b, so we proceed to Line 5. Finally, Line 5 does not cross either polygon, making it the correct upper tangent for the given polygons.
For finding the lower tangent we need to move inversely through the polygons i.e. if the line is crossing the polygon b we move to clockwise next and to anti-clockwise next if the line is crossing the polygon a.
Algorithm for upper tangent:
L ← line joining the rightmost point of a
and leftmost point of b.
while (L crosses any of the polygons)
{
while(L crosses b)
L ← L' : the point on b moves up.
while(L crosses a)
L ← L' : the point on a moves up.
}
Algorithm for lower tangent:
L ← line joining the rightmost point of a
and leftmost point of b.
while (L crosses any of the polygons)
{
while (L crosses b)
L ← L' : the point on b moves down.
while (L crosses a)
L ← L' : the point on a moves down.
}
Note that the above code only computes the upper tangent. A similar approach can be used to find the lower tangent as well.
CPP
#include<bits/stdc++.h>usingnamespacestd;// Determines the quadrant of a point relative to originintquad(vector<int>p){if(p[0]>=0&&p[1]>=0)return1;if(p[0]<=0&&p[1]>=0)return2;if(p[0]<=0&&p[1]<=0)return3;return4;}// Returns the orientation of ordered triplet (a, b, c)// 0 -> Collinear, 1 -> Clockwise, -1 -> Counterclockwiseintorientation(vector<int>a,vector<int>b,vector<int>c){intres=(b[1]-a[1])*(c[0]-b[0])-(c[1]-b[1])*(b[0]-a[0]);if(res==0)return0;if(res>0)return1;return-1;}// Compare function to sort points counter-clockwise around centerboolcompare(vector<int>p1,vector<int>q1,vector<int>mid){vector<int>p={p1[0]-mid[0],p1[1]-mid[1]};vector<int>q={q1[0]-mid[0],q1[1]-mid[1]};intone=quad(p);inttwo=quad(q);if(one!=two)return(one<two);return(p[1]*q[0]<q[1]*p[0]);}// Sorts the polygon points counter-clockwisevector<vector<int>>sortPoints(vector<vector<int>>polygon){vector<int>mid={0,0};intn=polygon.size();// Calculate center (centroid) of the polygonfor(inti=0;i<n;i++){mid[0]+=polygon[i][0];mid[1]+=polygon[i][1];polygon[i][0]*=n;polygon[i][1]*=n;}// Sort points based on their angle from the centersort(polygon.begin(),polygon.end(),[mid](vector<int>p1,vector<int>p2){returncompare(p1,p2,mid);});// Divide back to original coordinatesfor(inti=0;i<n;i++){polygon[i][0]/=n;polygon[i][1]/=n;}returnpolygon;}// Finds the upper tangent between two convex polygons a and b// Returns two points forming the upper tangentvector<vector<int>>findUpperTangent(vector<vector<int>>a,vector<vector<int>>b){intn1=a.size(),n2=b.size();// Find the rightmost point of polygon a and leftmost point of polygon bintmaxa=INT_MIN;for(auto&p:a)maxa=max(maxa,p[0]);intminb=INT_MAX;for(auto&p:b)minb=min(minb,p[0]);// Sort both polygons counter-clockwisea=sortPoints(a);b=sortPoints(b);// Ensure polygon a is to the left of polygon bif(minb<maxa)swap(a,b);n1=a.size();n2=b.size();// Find the rightmost point in aintia=0,ib=0;for(inti=1;i<n1;i++)if(a[i][0]>a[ia][0])ia=i;// Find the leftmost point in bfor(inti=1;i<n2;i++)if(b[i][0]<b[ib][0])ib=i;// Initialize starting pointsintinda=ia,indb=ib;booldone=false;// Find upper tangent using orientation checkswhile(!done){done=true;// Move to next point in a if necessarywhile(orientation(b[indb],a[inda],a[(inda+1)%n1])>0)inda=(inda+1)%n1;// Move to previous point in b if necessarywhile(orientation(a[inda],b[indb],b[(n2+indb-1)%n2])<0){indb=(n2+indb-1)%n2;done=false;}}// Return the points forming the upper tangentreturn{a[inda],b[indb]};}// Main driver codeintmain(){vector<vector<int>>a={{2,2},{3,1},{3,3},{5,2},{4,0}};vector<vector<int>>b={{0,1},{1,0},{0,-2},{-1,0}};vector<vector<int>>tangent=findUpperTangent(a,b);for(autoit:tangent){cout<<it[0]<<" "<<it[1]<<"\n";}return0;}
Java
importjava.util.*;classGfG{// Determines the quadrant of a pointstaticintquad(int[]p){if(p[0]>=0&&p[1]>=0)return1;if(p[0]<=0&&p[1]>=0)return2;if(p[0]<=0&&p[1]<=0)return3;return4;}// Checks whether the line is crossing the polygonstaticintorientation(int[]a,int[]b,int[]c){intres=(b[1]-a[1])*(c[0]-b[0])-(c[1]-b[1])*(b[0]-a[0]);if(res==0)return0;if(res>0)return1;return-1;}// Compare function for sortingstaticclassPointComparatorimplementsComparator<int[]>{int[]mid;publicPointComparator(int[]mid){this.mid=mid;}publicintcompare(int[]p1,int[]p2){int[]p={p1[0]-mid[0],p1[1]-mid[1]};int[]q={p2[0]-mid[0],p2[1]-mid[1]};intone=quad(p);inttwo=quad(q);if(one!=two)returnone-two;returnp[1]*q[0]-q[1]*p[0];}}// Finds upper tangent of two polygons 'a' and 'b'// represented as 2D arrays and stores the resultstaticint[][]findUpperTangent(int[][]a,int[][]b){// n1 -> number of points in polygon a// n2 -> number of points in polygon bintn1=a.length,n2=b.length;int[]mid={0,0};intmaxa=Integer.MIN_VALUE;// Calculate centroid for polygon a and adjust points for scalingfor(inti=0;i<n1;i++){maxa=Math.max(maxa,a[i][0]);mid[0]+=a[i][0];mid[1]+=a[i][1];a[i][0]*=n1;a[i][1]*=n1;}// Sorting the points in counter-clockwise order for polygon aArrays.sort(a,newPointComparator(mid));for(inti=0;i<n1;i++){a[i][0]/=n1;a[i][1]/=n1;}mid[0]=0;mid[1]=0;intminb=Integer.MAX_VALUE;// Calculate centroid for polygon b and adjust points for scalingfor(inti=0;i<n2;i++){mid[0]+=b[i][0];mid[1]+=b[i][1];minb=Math.min(minb,b[i][0]);b[i][0]*=n2;b[i][1]*=n2;}// Sorting the points in counter-clockwise order for polygon bArrays.sort(b,newPointComparator(mid));for(inti=0;i<n2;i++){b[i][0]/=n2;b[i][1]/=n2;}// If a is to the right of b, swap a and bif(minb<maxa){int[][]temp=a;a=b;b=temp;n1=a.length;n2=b.length;}// ia -> rightmost point of aintia=0,ib=0;for(inti=1;i<n1;i++){if(a[i][0]>a[ia][0])ia=i;}// ib -> leftmost point of bfor(inti=1;i<n2;i++){if(b[i][0]<b[ib][0])ib=i;}// Finding the upper tangentintinda=ia,indb=ib;booleandone=false;while(!done){done=true;while(orientation(b[indb],a[inda],a[(inda+1)%n1])>0)inda=(inda+1)%n1;while(orientation(a[inda],b[indb],b[(n2+indb-1)%n2])<0){indb=(n2+indb-1)%n2;done=false;}}// Returning the upper tangent as a 2D arrayreturnnewint[][]{{a[inda][0],a[inda][1]},{b[indb][0],b[indb][1]}};}// Driver codepublicstaticvoidmain(String[]args){int[][]a={{2,2},{3,1},{3,3},{5,2},{4,0}};int[][]b={{0,1},{1,0},{0,-2},{-1,0}};// Get the upper tangent as a 2D arrayint[][]upperTangent=findUpperTangent(a,b);// Store or use the resultSystem.out.println(upperTangent[0][0]+" "+upperTangent[0][1]);System.out.println(upperTangent[1][0]+" "+upperTangent[1][1]);}}
// Determine the quadrant of a pointfunctionquad(p){if(p[0]>=0&&p[1]>=0)return1;if(p[0]<=0&&p[1]>=0)return2;if(p[0]<=0&&p[1]<=0)return3;return4;}// Find orientation of triplet (a, b, c)functionorientation(a,b,c){letres=(b[1]-a[1])*(c[0]-b[0])-(c[1]-b[1])*(b[0]-a[0]);if(res===0)return0;returnres>0?1:-1;}// Compare two points based on midfunctioncompare(p1,p2,mid){letp=[p1[0]-mid[0],p1[1]-mid[1]];letq=[p2[0]-mid[0],p2[1]-mid[1]];letquadP=quad(p);letquadQ=quad(q);if(quadP!==quadQ)returnquadP-quadQ;return(p[1]*q[0])-(q[1]*p[0]);}// Sort polygon points counter-clockwisefunctionsortPoints(polygon){letn=polygon.length;letmid=[0,0];for(leti=0;i<n;i++){mid[0]+=polygon[i][0];mid[1]+=polygon[i][1];polygon[i][0]*=n;polygon[i][1]*=n;}polygon.sort((p1,p2)=>compare(p1,p2,mid));for(leti=0;i<n;i++){polygon[i][0]=Math.floor(polygon[i][0]/n);polygon[i][1]=Math.floor(polygon[i][1]/n);}returnpolygon;}// Find upper tangent between two convex polygonsfunctionfindUpperTangent(a,b){letn1=a.length;letn2=b.length;letmaxa=-Infinity;for(leti=0;i<n1;i++)maxa=Math.max(maxa,a[i][0]);letminb=Infinity;for(leti=0;i<n2;i++)minb=Math.min(minb,b[i][0]);a=sortPoints(a);b=sortPoints(b);if(minb<maxa){lettemp=a;a=b;b=temp;n1=a.length;n2=b.length;}letia=0,ib=0;for(leti=1;i<n1;i++)if(a[i][0]>a[ia][0])ia=i;for(leti=1;i<n2;i++)if(b[i][0]<b[ib][0])ib=i;letinda=ia,indb=ib;letdone=false;while(!done){done=true;while(orientation(b[indb],a[inda],a[(inda+1)%n1])>0)inda=(inda+1)%n1;while(orientation(a[inda],b[indb],b[(n2+indb-1)%n2])<0){indb=(n2+indb-1)%n2;done=false;}}return[a[inda],b[indb]];}// Driver codeleta=[[2,2],[3,1],[3,3],[5,2],[4,0]];letb=[[0,1],[1,0],[0,-2],[-1,0]];lettangent=findUpperTangent(a,b);for(letpointoftangent){console.log(point[0]+" "+point[1]);}