reflect-3.js

total 0
used 0
limit 0
/* categories: reflections files: head stage ../point_src/point-content.js stroke point ../point_src/pointlistpen.js ../point_src/pointlist.js mouse dragging ../point_src/constrain-distance.js */ class MainStage extends Stage { // canvas = document.getElementById('playspace'); canvas = 'playspace' mounted(){ // ray beam this.ray = new PointList( new Point(250, 150, 10) , new Point(400, 320, 10) ) // A Line representing the plane in 2d (front view) this.plane = new PointList( new Point(200, 300, 10) , new Point(500, 300, 10) ) this.dragging.add(...this.ray, ...this.plane) } draw(ctx){ this.clear(ctx) let ray = this.ray; let line = this.plane; let rayBeam = {start: ray[0], end: ray[1]} // ray beam from 0 to 1 ray[0].lookAt(ray[1]) ray[1].lookAt(ray[0]) ray.pen.indicators(ctx) // Draw the plane line.pen.line(ctx, {color:'#AAA', width: 3}) let planeRay = {start: line[0], end: line[1]} let planeLen = distance(line[0], line[1]) // let p = checkIntersection(planeRay, rayBeam, planeLen) let hitPoint = checkIntersection(planeRay, rayBeam, planeLen) let p1 = this.center if(!hitPoint) { p1.copy().update({ radius: 10 , radians: getBounceAngle(ray[1], planeRay) }).pen.indicator(ctx, {color: 'red'}) return } p1 = new Point(hitPoint) p1.radius = 20 /* inbound angle, pointing at the first point. */ // p1.pen.line(ctx, null, 'green', 2) /* symmetry angle, inverse of the inbound */ // const mirrorPoint = p1.copy().update({ // radius: 20 // , radians: getAngle(hitPoint, planeRay) // }) // mirrorPoint.pen.indicator(ctx, {color: 'gray'}) /* reflect angle.*/ const reflectPoint = p1.copy().update({ radius: 20 , radians: getBounceAngle(hitPoint, planeRay) }) let overLen = distance(reflectPoint, ray[1]) reflectPoint.project(overLen).pen.indicator(ctx, {color: 'gray'}) reflectPoint.pen.line(ctx, null, 'red', 2) } } const checkIntersection = function(planeLine, raybeam, length) { const x1 = planeLine.start.x; const y1 = planeLine.start.y; if(length == undefined) { length = distance(planeLine.start, planeLine.end) } // Normalize the direction vector (end - start) and apply the length const dx = planeLine.end.x - x1; const dy = planeLine.end.y - y1; const magnitude = Math.sqrt(dx * dx + dy * dy); let directionX = (dx / magnitude) * length; let directionY = (dy / magnitude) * length; const x2 = planeLine.start.x + directionX; const y2 = planeLine.start.y + directionY; const x3 = raybeam.start.x; const y3 = raybeam.start.y; const x4 = raybeam.end.x; const y4 = raybeam.end.y; const denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4); if (denom === 0) return false; // Parallel lines const t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / denom; const u = -((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3)) / denom; if (t > 0 && t < 1 && u > 0 && u < 1) { const intersectX = x1 + t * (x2 - x1); const intersectY = y1 + t * (y2 - y1); // Calculate the angle from the intersection point to the start of raybeam const angleRad = Math.atan2(y3 - intersectY, x3 - intersectX); return { x: intersectX, y: intersectY, radians: angleRad }; } return false; } /* Reflect _through_ the ray, landing on the opposite side of the ray */ function getAngle(point, line) { // Step 1: Convert the incident angle (from radians) to a vector const incidentVectorX = Math.cos(point.radians); const incidentVectorY = Math.sin(point.radians); // Step 2: Calculate the normal of the line (perpendicular to the line) const dx = line.end.x - line.start.x; const dy = line.end.y - line.start.y; // The normal vector can be (-dy, dx) or (dy, -dx) const normalX = -dy; const normalY = dx; // Normalize the normal vector const normalMagnitude = Math.sqrt(normalX * normalX + normalY * normalY); const normalUnitX = normalX / normalMagnitude; const normalUnitY = normalY / normalMagnitude; // Step 3: Reflect the incident vector using the normal vector const dotProduct = incidentVectorX * normalUnitX + incidentVectorY * normalUnitY; const reflectVectorX = incidentVectorX - 2 * dotProduct * normalUnitX; const reflectVectorY = incidentVectorY - 2 * dotProduct * normalUnitY; // Step 4: Convert the reflected vector back to an angle in radians const reflectAngle = Math.atan2(reflectVectorY, reflectVectorX); return reflectAngle; } function getAngleAlt(point, line) { // Step 1: Convert the incident angle (from radians) to a vector const incidentVectorX = Math.cos(point.radians); const incidentVectorY = Math.sin(point.radians); // Step 2: Calculate the normal of the line (perpendicular to the line) const dx = line.end.x - line.start.x; const dy = line.end.y - line.start.y; // The normal vector can be (-dy, dx) or (dy, -dx) let normalX = -dy; let normalY = dx; // Normalize the normal vector const normalMagnitude = Math.sqrt(normalX * normalX + normalY * normalY); let normalUnitX = normalX / normalMagnitude; let normalUnitY = normalY / normalMagnitude; // Step 3: Check the dot product of the incident vector and the normal const dotProductIncidentNormal = incidentVectorX * normalUnitX + incidentVectorY * normalUnitY; // If the dot product is positive, flip the normal vector if (dotProductIncidentNormal > 0) { normalUnitX = -normalUnitX; normalUnitY = -normalUnitY; } // Step 4: Reflect the incident vector using the correct normal vector const dotProduct = incidentVectorX * normalUnitX + incidentVectorY * normalUnitY; const reflectVectorX = incidentVectorX - 2 * dotProduct * normalUnitX; const reflectVectorY = incidentVectorY - 2 * dotProduct * normalUnitY; // Step 5: Convert the reflected vector back to an angle in radians const reflectAngle = Math.atan2(reflectVectorY, reflectVectorX); return reflectAngle; } function getBounceAngle(point, line) { // Step 1: Convert the incident angle (from radians) to a vector const incidentVectorX = -Math.cos(point.radians); const incidentVectorY = -Math.sin(point.radians); // Step 2: Calculate the normal of the line (perpendicular to the line) const dx = line.end.x - line.start.x; const dy = line.end.y - line.start.y; // The normal vector should point outwards from the surface const normalX = -dy; const normalY = dx; // Normalize the normal vector const normalMagnitude = Math.sqrt(normalX * normalX + normalY * normalY); const normalUnitX = normalX / normalMagnitude; const normalUnitY = normalY / normalMagnitude; // Step 3: Calculate the dot product of the incident vector and the normal const dotProduct = incidentVectorX * normalUnitX + incidentVectorY * normalUnitY; // Step 4: Reflect the incident vector off the line (like a bounce) const reflectVectorX = incidentVectorX - 2 * dotProduct * normalUnitX; const reflectVectorY = incidentVectorY - 2 * dotProduct * normalUnitY; // Step 5: Convert the reflected vector back to an angle in radians const reflectAngle = Math.atan2(reflectVectorY, reflectVectorX); return reflectAngle; } function getReflectAngle(intersectionPoint, line, otherLine) { // Incident vector (from the ray's start to intersection point) const incidentVectorX = line.end.x - line.start.x; const incidentVectorY = line.end.y - line.start.y; // Normalize the incident vector const incidentMagnitude = Math.sqrt(incidentVectorX * incidentVectorX + incidentVectorY * incidentVectorY); const incidentUnitX = incidentVectorX / incidentMagnitude; const incidentUnitY = incidentVectorY / incidentMagnitude; // Normal vector to the other line (perpendicular to the line) const dx = otherLine.end.x - otherLine.start.x; const dy = otherLine.end.y - otherLine.start.y; // The normal can be (-dy, dx) or (dy, -dx), depending on which direction you're considering const normalX = -dy; const normalY = dx; // Normalize the normal vector const normalMagnitude = Math.sqrt(normalX * normalX + normalY * normalY); const normalUnitX = normalX / normalMagnitude; const normalUnitY = normalY / normalMagnitude; // Reflect the incident vector around the normal const dotProduct = incidentUnitX * normalUnitX + incidentUnitY * normalUnitY; const reflectVectorX = incidentUnitX - 2 * dotProduct * normalUnitX; const reflectVectorY = incidentUnitY - 2 * dotProduct * normalUnitY; // Calculate the reflection angle const reflectAngle = Math.atan2(reflectVectorY, reflectVectorX); return reflectAngle; } const checkPointIntersection = function(line, point, radius=5, length=400) { const x1 = line.start.x; const y1 = line.start.y; // Normalize the direction vector (end - start) and apply the length const dx = line.end.x - x1; const dy = line.end.y - y1; const magnitude = Math.sqrt(dx * dx + dy * dy); let directionX = (dx / magnitude) * length; let directionY = (dy / magnitude) * length; const x2 = line.start.x + directionX; const y2 = line.start.y + directionY; // The coordinates of the point to check const px = point.x; const py = point.y; // Calculate the distance from the point to the line const distance = Math.abs((x2 - x1) * (y1 - py) - (x1 - px) * (y2 - y1)) / Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); // Check if the point is within the radius if (distance <= radius) { // Check if the point is within the bounds of the segment const dotProduct = (px - x1) * (x2 - x1) + (py - y1) * (y2 - y1); if (dotProduct >= 0 && dotProduct <= (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) { return true; } } return false; } const checkPointIntersectionExact = function(line, point, radius=5, length=400) { const x1 = line.start.x; const y1 = line.start.y; // Normalize the direction vector (end - start) and apply the length const dx = line.end.x - x1; const dy = line.end.y - y1; const magnitude = Math.sqrt(dx * dx + dy * dy); let directionX = (dx / magnitude) * length; let directionY = (dy / magnitude) * length; const x2 = line.start.x + directionX; const y2 = line.start.y + directionY; // The coordinates of the point to check const px = point.x; const py = point.y; // Calculate the distance from the point to the line const distance = Math.abs((x2 - x1) * (y1 - py) - (x1 - px) * (y2 - y1)) / Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); // Check if the point is within the radius if (distance <= radius) { // Calculate the projection of the point onto the line (closest point on the line) const t = ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / ((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); // Ensure the projection is within the line segment if (t >= 0 && t <= 1) { const intersectX = x1 + t * (x2 - x1); const intersectY = y1 + t * (y2 - y1); return { x: intersectX, y: intersectY }; } } return false; } const checkPointIntersectionWithRotation = function(line, point, radius=5, length=400) { const x1 = line.start.x; const y1 = line.start.y; // Normalize the direction vector (end - start) and apply the length const dx = line.end.x - x1; const dy = line.end.y - y1; const magnitude = Math.sqrt(dx * dx + dy * dy); let directionX = (dx / magnitude) * length; let directionY = (dy / magnitude) * length; const x2 = line.start.x + directionX; const y2 = line.start.y + directionY; // The coordinates of the point to check const px = point.x; const py = point.y; // Calculate the distance from the point to the line const distance = Math.abs((x2 - x1) * (y1 - py) - (x1 - px) * (y2 - y1)) / Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); // Check if the point is within the radius if (distance <= radius) { // Calculate the projection of the point onto the line (closest point on the line) const t = ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / ((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); // Ensure the projection is within the line segment if (t >= 0 && t <= 1) { const intersectX = x1 + t * (x2 - x1); const intersectY = y1 + t * (y2 - y1); // Calculate the angle of the ray relative to the vertical axis let angleRad = Math.atan2(dy, dx); let rotation = (angleRad * 180) / Math.PI; // Convert to degrees // Adjust rotation so that 0 degrees is straight up rotation = (rotation + 90) % 360; if (rotation < 0) { rotation += 360; } return { x: intersectX, y: intersectY, radians: angleRad }; // return { x: intersectX, y: intersectY, rotation: rotation }; } } return false; } stage = MainStage.go(/*{ loop: true }*/)
Run
Meta Data
imports ()
files ('head', 'stage', '../point_src/point-content.js', 'stroke', 'point', '../point_src/pointlistpen.js', '../point_src/pointlist.js', 'mouse', 'dragging', '../point_src/constrain-distance.js')
unused_keys ('title',)
unknown_keys ('categories',)
categories ['reflections']
filepath_exists True
path reflect-3.js
filepath reflect-3.js
clean_files ('../point_src/core/head.js', '../point_src/stage-resize.js', '../point_src/functions/resolve.js', '../point_src/stage.js', '../point_src/compass.js', '../point_src/center.js', '../point_src/point-content.js', '../point_src/setunset.js', '../point_src/stroke.js', '../point_src/pointpen.js', '../point_src/pointdraw.js', '../point_src/relative-xy.js', '../point_src/pointcast.js', '../point_src/point.js', '../point_src/pointlistpen.js', '../point_src/pointlistdraw.js', '../point_src/pointlistgradient.js', '../point_src/pointlistshape.js', '../point_src/pointlistgenerator.js', '../point_src/unpack.js', '../point_src/pointlist.js', '../point_src/events.js', '../point_src/automouse.js', '../point_src/functions/clamp.js', '../point_src/distances.js', '../point_src/protractor.js', '../point_src/text/beta.js', '../point_src/dragging.js', '../point_src/constrain-distance.js')
markdown {'html': '', 'content': 'categories: reflections\nfiles:\n head\n stage\n ../point_src/point-content.js\n stroke\n point\n ../point_src/pointlistpen.js\n ../point_src/pointlist.js\n mouse\n dragging\n ../point_src/constrain-distance.js'}