hi, i found some old code already posted here at forum
but give it some new show…
i not try to understand the math, just translated it into processing…
it is a math for a OUTER HULL,
not your OUTER LINE concept,
but possibly can be used,
as it fits your question too: “around a perimeter”
// https://www.geeksforgeeks.org/convex-hull-set-1-jarviss-algorithm-or-wrapping/
// 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.*;
GFG myset;
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 colinear
// 1 --> Clockwise
// 2 --> Counterclockwise
public 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 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, x, q) 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)
println("(" + temp.x + ", " + temp.y + ")");
}
/* Driver program to test above function */
public void make() {
points[0]=new Point(0, 3);
points[1]=new Point(2, 2);
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);
points[7]=new Point(4, 4);
}
public void hull() {
int n = points.length;
convexHull(points, n);
}
}
// This code is contributed by Arnav Kr. Mandal.
// mod processing KLL
Point[] points = new Point[8];
Vector<Point> hull = new Vector<Point>();
float zoom=100;
void setup(){
size(500,500);
myset = new GFG();
myset.make();
myset.hull();
}
void draw() {
background(200,200,0);
// translate(width/2,height/2);
translate(20,20);
// points
noStroke();
fill(200,0,0);
for ( int i = 0; i<points.length; i++) circle(points[i].x*zoom,points[i].y*zoom,5);
// result
stroke(0,200,0);
noFill();
int segs = hull.size();
for ( int i = 0; i<segs; i++) circle(hull.get(i).x*zoom,hull.get(i).y*zoom,7);
for ( int i = 0; i<segs; i++) {
float x1 = hull.get(i).x*zoom;
float y1 = hull.get(i).y*zoom;
int j = i+1;
if ( j == segs ) j = 0;
float x2 = hull.get(j).x*zoom;
float y2 = hull.get(j).y*zoom;
line(x1,y1,x2,y2);
}
}