This JavaScript program demonstrates how to check whether or not a point is inside a triangle on a canvas element.
The program generates 4 random points. The first 3 are designated A, B, and C and make up the triangle. The last point is designated as P and is check to see if it is inside the triangle.
The test uses an orientation check to see whether the point P is on the same side of directed sides AB, BC, and CA by checking that Area2() returns the same sign for each side. If so, the point is inside.
The form elements display the locations of the points, the Area2() checks, and the final result that display whether or not the point is inside.
<!DOCTYPE html> <html> <head> <title>XoaX.net's Javascript</title> <script type="text/javascript" src="PointInsideTriangle.js"></script> </head> <body onload="Draw()"> <canvas id="idCanvas" width="640" height ="480" style="background-color: #F0F0F0;"></canvas><br /> <form> <fieldset> <legend>Coordinates and Computations</legend> A: <input id="idA" type="text" size="40" /><br /> B: <input id="idB" type="text" size="40" /><br /> C: <input id="idC" type="text" size="40" /><br /> P: <input id="idP" type="text" size="40" /><br /> ABP Area: <input id="idABP" type="text" size="40" /><br /> BCP Area: <input id="idBCP" type="text" size="40" /><br /> CAP Area: <input id="idCAP" type="text" size="40" /><br /> P is Inside: <input type="radio" id="idIsInside"/> </fieldset> </form> </body> </html>
var gqCanvas = null; var gqContext = null; var gqPoints = null; class Point2D { constructor(dX, dY) { this.mdX = dX; this.mdY = dY; } // Get the signed area of the set of 3 points // The area is twice the area of the triangle since it actually the area of the parallelogram. // Det |(P1, 1), (P2, 1), (P3, 1)|, where 1 is appended as the third coordinate // The sign is positive for clockwise orientations because the pixel coordinates have the opposite orientation static Area2(qP1, qP2, qP3) { //return qP1.mdX*(qP2.mdY - qP3.mdY) + qP1.mdY*(qP3.mdX - qP2.mdX) + (qP2.mdX*qP3.mdY - qP3.mdX*qP2.mdY); // This form uses 2 products, 4 subtractions and 1 addition return (qP2.mdX - qP1.mdX)*(qP3.mdY - qP1.mdY) + (qP1.mdY - qP2.mdY)*(qP3.mdX - qP1.mdX); } DrawPoint(qContext2D) { qContext2D.fillStyle = "gray"; qContext2D.beginPath(); qContext2D.arc(this.mdX, this.mdY, 3, 0, 2.0*Math.PI, true); qContext2D.fill(); } DrawLabeledPoint(qContext2D, sLabel) { this.DrawPoint(qContext2D); qContext2D.fillText(sLabel, this.mdX, this.mdY + 15); } } function Initialize() { gqCanvas = document.getElementById("idCanvas"); gqContext = gqCanvas.getContext("2d"); gqPoints = []; // Get the size of the canvas const kiWidth = gqCanvas.width; const kiHeight = gqCanvas.height; // Generate the set of 4 points for (var i = 0; i < 4; ++i) { gqPoints.push(new Point2D(20 + (kiWidth - 40)*Math.random(),20 + (kiHeight - 40)*Math.random())); } } function Draw() { // Generate a set of four points Initialize(); // Call the four points A, B, C, and P let inA = document.getElementById("idA"); inA.value="(" +gqPoints[0].mdX+ ", " +gqPoints[0].mdY+ ")"; let inB = document.getElementById("idB"); inB.value="(" +gqPoints[1].mdX+ ", " +gqPoints[1].mdY+ ")"; let inC = document.getElementById("idC"); inC.value="(" +gqPoints[2].mdX+ ", " +gqPoints[2].mdY+ ")"; let inP = document.getElementById("idP"); inP.value="(" +gqPoints[3].mdX+ ", " +gqPoints[3].mdY+ ")"; // Take AB, BC, and CA and check whether P is on the same side of each one. const kdAreaABP = Point2D.Area2(gqPoints[0], gqPoints[1], gqPoints[3]); let inABP = document.getElementById("idABP"); inABP.value=kdAreaABP; const kdAreaBCP = Point2D.Area2(gqPoints[1], gqPoints[2], gqPoints[3]); let inBCP = document.getElementById("idBCP"); inBCP.value=kdAreaBCP; const kdAreaCAP = Point2D.Area2(gqPoints[2], gqPoints[0], gqPoints[3]); let inCAP = document.getElementById("idCAP"); inCAP.value=kdAreaCAP; // Note: The sign determines the side that the third point is on. // If all three segements have the same sign relative to p, it is on the inside. let inIsInside = document.getElementById("idIsInside"); if (kdAreaABP*kdAreaBCP > 0.0 && kdAreaABP*kdAreaCAP > 0.0) { inIsInside.checked = true; } else { inIsInside.checked = false; } // Draw a triangle around the first three points gqContext.beginPath(); gqContext.moveTo(gqPoints[0].mdX, gqPoints[0].mdY); for(var i = 1; i < 3; ++i) { gqContext.lineTo(gqPoints[i].mdX, gqPoints[i].mdY); } gqContext.closePath(); gqContext.strokeStyle = "red"; gqContext.lineWidth = 1; gqContext.stroke(); // Draw the points and labels // Label them A, B, C, and P var saLabels = ["A", "B", "C", "P"]; for(var i = 0; i < 4; ++i) { gqPoints[i].DrawLabeledPoint(gqContext, saLabels[i]); } }
© 20072025 XoaX.net LLC. All rights reserved.