reflect-4.js

total 0
used 0
limit 0
/* title: Point Reflection V3 categories: reflections files: head stage ../point_src/point-content.js ../point_src/intersections.js stroke point pointlist mouse dragging */ 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; ray.pen.fill(ctx, 'purple', 8) // Draw the plane mirror line line.pen.line(ctx, {color:'#AAA', width: 3}) let planeLen = line[0].distanceTo(line[1]) let hitPoint = checkIntersection(line, ray, planeLen) let p1 = this.center if(!hitPoint) { p1.copy().update({ radius: 10 , radians: getBounceAngle(ray[1], line) }).pen.indicator(ctx, {color: 'red'}) return } const reflectPoint = new Point(hitPoint) reflectPoint.update({ radius: 20 , radians: getBounceAngle(reflectPoint, line) }) let overLen = reflectPoint.distanceTo(ray[1]) reflectPoint.project(overLen).pen.indicator(ctx, {color: 'gray'}) ray[0].pen.line(ctx, hitPoint , 'red', 2) reflectPoint.pen.line(ctx, null, 'red', 2) } } const checkIntersection = function(planeLine, raybeam, length) { const x1 = planeLine[0].x; const y1 = planeLine[0].y; if(length == undefined) { length = distance(planeLine[0], planeLine[1]) } // Normalize the direction vector (end - start) and apply the length const dx = planeLine[1].x - x1; const dy = planeLine[1].y - y1; const magnitude = Math.sqrt(dx * dx + dy * dy); let directionX = (dx / magnitude) * length; let directionY = (dy / magnitude) * length; const x2 = planeLine[0].x + directionX; const y2 = planeLine[0].y + directionY; const x3 = raybeam[0].x; const y3 = raybeam[0].y; const x4 = raybeam[1].x; const y4 = raybeam[1].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; } function getBounceAngle(point, line) { /* Calculates the reflection angle of a point hitting a line segment. This function simulates a perfect elastic collision (like a billiard ball or light ray). It converts an incident angle into a vector, calculates the surface normal, and applies the standard reflection formula: R = I - 2(I ยท N)N. Reflection Logic: 1. Convert incident angle to a unit vector. 2. Derive the surface normal from the line's direction. 3. Use the Dot Product to find the projection of the incident vector onto the normal. 4. Subtract twice that projection from the incident vector to get the reflection. 5. Convert back to radians using atan2. */ // Step 1: Convert the incident angle (from radians) to a vector const incidentVector = point.vector2D(-1) // Step 2: Calculate the normal of the line (perpendicular to the line) const dx = line[1].x - line[0].x; const dy = line[1].y - line[0].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 = incidentVector.x * normalUnitX + incidentVector.y * normalUnitY; // Step 4: Reflect the incident vector off the line (like a bounce) const reflectVectorX = incidentVector.x - 2 * dotProduct * normalUnitX; const reflectVectorY = incidentVector.y - 2 * dotProduct * normalUnitY; // Step 5: Convert the reflected vector back to an angle in radians const reflectAngle = Math.atan2(reflectVectorY, reflectVectorX); return reflectAngle; } stage = MainStage.go(/*{ loop: true }*/)
Run
Meta Data
title Point Reflection V3
imports ()
files ('head', 'stage', '../point_src/point-content.js', '../point_src/intersections.js', 'stroke', 'point', 'pointlist', 'mouse', 'dragging')
unused_keys ()
unknown_keys ('categories',)
categories ['reflections']
filepath_exists True
path reflect-4.js
filepath reflect-4.js
clean_files ('../point_src/core/head.js', '../point_src/stage-hooks.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/intersections.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/pointlistdraw.js', '../point_src/pointlistgradient.js', '../point_src/pointlistshape.js', '../point_src/pointlistgenerator.js', '../point_src/unpack.js', '../point_src/pointlist.js', '../point_src/pointlistpen.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')
markdown {'html': '', 'content': 'title: Point Reflection V3\ncategories: reflections\nfiles:\n head\n stage\n ../point_src/point-content.js\n ../point_src/intersections.js\n stroke\n point\n pointlist\n mouse\n dragging'}