This commit is contained in:
Jay
2026-03-10 21:01:46 +00:00
commit 9006b2e06a
242 changed files with 30823 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
class dot{
constructor(x, y){
this.x = x;
this.y = y;
}
}

View File

@@ -0,0 +1,90 @@
<?php
if($_SERVER['HTTP_X_FORWARDED_PROTO'] !== 'https') {
header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
die();
}
?>
<DOCTYPE! html>
<html>
<title>Convex Hull</title>
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Inconsolata" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="style.css">
<script
src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.2.0/p5.min.js"
integrity="sha512-b/htz6gIyFi3dwSoZ0Uv3cuv3Ony7EeKkacgrcVg8CMzu90n777qveu0PBcbZUA7TzyENGtU+qZRuFAkfqgyoQ=="
crossorigin="anonymous"
></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/latest.js?config=AM_CHTML"></script>
<button id="backButton"
onclick="window.location.href='../../tutorials.html'">Back</button>
<head>
<h1>Convex Hull - Jarvis' Marsh</h1>
<p>A convex hull is where a convex polygon is constructed to bound a set of points on a 2D plane. So, given all points in the set P, what is the smallest convex polygon we can construct that bounds all points in P.</p><br>
<p>Pseudo code:</p>
<div class="psudoCode">
<ul>
<li>Randomly place n points on a 2D plane.</li>
<li>Find the leftmost point/the point with the smallest x value. Called `gamma`.</li>
<li>Find the vector which is the <i>most left</i> which connects `gamma` to point q in set P.</li>
<li>Store `gamma` and q in a list and repeat until q = `gamma`.</li>
</div>
<br>
</head>
<body>
<p>This canvas starts off by generating a set amount of points, placing them at random locations around the screen and adding them to an array. It then finds the index of the point in the array - `vertices[]` - with the lowest x value. It then loops through the array finding all vector's originating from `gamma`, <a>`vec(gammaP(i))`</a>.</p>
<p>We then examine each vertex and evaluate which one is the <i>leftmost</i> from the perspective of point `gamma`. Say in this case `P(q)` is the leftmost vector so we push q onto the stack.</p><br>
<p>Stack: `((q), (gamma))`</p><br>
<p>We then repeat until we reach our starting point, which in this case means our starting point is the same as the next point (`q=gamma`)</p>
<img class="examples" src="stepByStep.png">
<p>Now the question of how to calculate the <i>leftness</i> of a vector compared to another. We can use the <a>cross product</a> in 2D.</p>
<p><a>`vecu times vecv = u`<sub>`x`</sub>`*v`<sub>`y`</sub>` - u`<sub>`y`</sub>`*v`<sub>`x`</sub></a> If the cross product is greater than 0, the vector is to the left. If it is equal to 0 then the vectors are colinear</p>
<p><b>Note:</b> to convert coordinates to a vector, find the difference between your origin point and your target point</p>
<div class="psudoCode">
<a>for (var i = 0; i < vertices.length; i++){</a><br>
<a>&nbsp;if (i != originPoint){</a><br>
<a>&nbsp;&nbsp;x1 = vertices[recordLeftVector].x - vertices[originPoint].x;</a><br>
<a>&nbsp;&nbsp;y1 = vertices[recordLeftVector].y - vertices[originPoint].y;</a><br><br>
<a>&nbsp;&nbsp;x2 = vertices[i].x - vertices[originPoint].x;</a><br>
<a>&nbsp;&nbsp;y2 = vertices[i].y - vertices[originPoint].y;</a><br><br>
<a>&nbsp;&nbsp;if ((y2 * x1) - (y1 * x2) <= 0){</a><br>
<a>&nbsp;&nbsp;&nbsp;recordLeftVector = i;</a><br>
<a>&nbsp;&nbsp;}</a><br>
<a>&nbsp;}</a><br>
<a>}</a><br>
</div>
<p>Now we just have to add in a little piece of code at the bottom of this function to: increment the iteration number so we don't recurse until eternity, add our leftmost vector to the route stack and call the function again with the next point as a parameter.</p>
<div class="psudoCode">
<a>if (originPoint != recordLeftVector && iterations < 75){</a><br>
<a>&nbsp;&nbsp;route[iterations] = recordLeftVector;</a><br>
<a>&nbsp;&nbsp;iterations += 1;</a><br>
<a>&nbsp;&nbsp;findLeftLine(recordLeftVector);</a><br>
<a>}</a><br>
</div><br><br>
</body>
<script src="sketch.js"></script>
<script src="dot.js"></script>
<!--https://www.youtube.com/watch?v=Vu84lmMzP2o<br>
http://jeffe.cs.illinois.edu/teaching/compgeom/notes/01-convexhull.pdf</p>-->
</html>

View File

@@ -0,0 +1,102 @@
var jarvisMarsh = function( p ){
const numPoints = 12;
var vertices = [];
var route = [];
let iterations = 0;
p.setup = function(){
p.createCanvas(750, 500);
p.background(217);
button = p.createButton('Reset Button')
button.mousePressed(p.resetSketch);
p.initValues();
}
p.draw = function(){}
p.drawLine = function(){
let r = p.findLeftPoint();
route[iterations] = r;
p.findLeftLine(r);
p.stroke(215, 75, 75);
p.strokeWeight(1);
for (var i = 0; i < route.length - 1; i++){
p.line(vertices[route[i]].x, vertices[route[i]].y, vertices[route[i+1]].x, vertices[route[i+1]].y)
}
}
p.findLeftLine = function(originPoint){
var recordLeftVector = 1;
let x1, x2, y1, y2;
for (var i = 0; i < vertices.length; i++){
if (i != originPoint){
x1 = vertices[recordLeftVector].x - vertices[originPoint].x;
y1 = vertices[recordLeftVector].y - vertices[originPoint].y;
x2 = vertices[i].x - vertices[originPoint].x;
y2 = vertices[i].y - vertices[originPoint].y;
//if the result if positive then vector u is left of vector v
//where u and v are both vectors from the target point
//If its equal to 0 then they're colinear. This is also good :)
if ((y2 * x1) - (y1 * x2) <= 0){
recordLeftVector = i;
}
}
}
if (originPoint != recordLeftVector && iterations < 75){
route[iterations] = recordLeftVector;
iterations += 1;
p.findLeftLine(recordLeftVector);
}
}
p.findLeftPoint = function(){
let recordLeft = 0;
for (var i = 0; i < vertices.length; i++){
if (vertices[i].x < vertices[recordLeft].x){
recordLeft = i;
}
}
return recordLeft;
}
p.resetSketch = function(){
vertices.length = 0;
p.clear()
p.background(217);
p.initValues();
p.findLeftLine();
p.draw();
}
p.initValues = function(){
p.stroke(0);
p.strokeWeight(7);
var bufferx = p.width * 0.0625;
var buffery = p.height * 0.0625;
for (var i = 0; i < numPoints; i++){
vertices[i] = new dot(p.random(bufferx, p.width - bufferx), p.random(buffery, p.height - buffery));
p.point(vertices[i].x, vertices[i].y);
}
iterations = 0;
p.drawLine();
}
};
var myp5 = new p5(jarvisMarsh, 'c1');

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

@@ -0,0 +1,71 @@
h1{
font-family: 'Roboto Condensed', sans-serif;
margin: 0;
padding: 0 0 15px 0;
font-weight: 700;
font-size: 32px;
}
h2{
font-family: 'Roboto Condensed', sans-serif;
margin: 0;
padding: 15px 0 15px 0;
font-weight: 650;
font-size: 20px;
}
p{
margin: 1px;
font-family: 'Roboto', sans-serif;
font-size: 19px;
padding: 5px 0px 5px 0px;
}
.psudoCode{
font-family: 'Inconsolata', monospace;
font-size: 19px;
background-color: #D9D9D9;
border: 1px solid;
padding: 5px;
box-shadow: 5px 5px #888888;
}
a{
font-family: 'Inconsolata', monospace;
font-size: 19px;
background-color: #D9D9D9;
}
button{
background-color: white;
border: 2px solid #555555;
color: black;
padding: 16px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 4px 2px;
-webkit-transition-duration: 0.4s; /* Safari */
transition-duration: 0.4s;
cursor: pointer;
float:right;
}
button:hover {
background-color: #555555;
color: white;
}
.examples{
padding: 10px;
}
html{
-webkit-user-select: none; /* Safari */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* IE10+/Edge */
user-select: none; /* Standard */
}