Skip to content

Commit

Permalink
Vector calculation for segment intersection
Browse files Browse the repository at this point in the history
  • Loading branch information
monman53 committed Jun 22, 2024
1 parent 0a8b38c commit dd23854
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 34 deletions.
12 changes: 6 additions & 6 deletions src/Canvas.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { watch, onMounted, ref } from 'vue'
import { state, lights, lens, sensor, sensorData, apple, options, style, lensR, lensD, infR } from './globals'
import { Vec, vec, vecRad, getIntersectionY, getIntersectionLens, crossAngle, fGaussian } from './math'
import { Vec, vec, vecRad, getIntersectionLens, crossAngle, fGaussian, intersectionSS } from './math'
import { Light } from './type'
Expand Down Expand Up @@ -56,7 +56,7 @@ const drawRay = (image: Vec, s0: Vec, s: Vec, v: Vec, color: number, sensorDataT
// Collision to aperture
//--------------------------------
if (options.value.aperture) {
const p = getIntersectionY(s, v, lens.value.x, -lens.value.r, lens.value.r)
const p = intersectionSS(s, s.add(v.normalize().mul(infR.value)), vec(lens.value.x, -lens.value.r), vec(lens.value.x, lens.value.r))
if (p) {
const upperHit = p.y > lens.value.aperture * lens.value.r
const lowerHit = p.y < -lens.value.aperture * lens.value.r
Expand Down Expand Up @@ -93,7 +93,7 @@ const drawRay = (image: Vec, s0: Vec, s: Vec, v: Vec, color: number, sensorDataT
// Collision to ideal lens
//--------------------------------
if (options.value.lensIdeal && options.value.lens) {
const p = getIntersectionY(s, v, lens.value.x, -lens.value.r, lens.value.r)
const p = intersectionSS(s, s.add(v.normalize().mul(infR.value)), vec(lens.value.x, -lens.value.r), vec(lens.value.x, lens.value.r))
if (p) {
v = p.sub(s)
s = drawSegment(s, v, v.length())
Expand All @@ -116,7 +116,7 @@ const drawRay = (image: Vec, s0: Vec, s: Vec, v: Vec, color: number, sensorDataT
if (options.value.body) {
// Upper
{
const p = getIntersectionY(s, v, lens.value.x, lens.value.r, infR.value);
const p = intersectionSS(s, s.add(v.normalize().mul(infR.value)), vec(lens.value.x, -infR.value), vec(lens.value.x, -lens.value.r))
if (p) {
v = p.sub(s)
drawSegment(s, v, v.length())
Expand All @@ -125,7 +125,7 @@ const drawRay = (image: Vec, s0: Vec, s: Vec, v: Vec, color: number, sensorDataT
}
// Lower
{
const p = getIntersectionY(s, v, lens.value.x, -infR.value, -lens.value.r);
const p = intersectionSS(s, s.add(v.normalize().mul(infR.value)), vec(lens.value.x, infR.value), vec(lens.value.x, lens.value.r))
if (p) {
v = p.sub(s)
drawSegment(s, v, v.length())
Expand All @@ -138,7 +138,7 @@ const drawRay = (image: Vec, s0: Vec, s: Vec, v: Vec, color: number, sensorDataT
// Collision to sensor
//--------------------------------
if (options.value.sensor) {
const p = getIntersectionY(s, v, sensor.value.x, -sensor.value.r, sensor.value.r);
const p = intersectionSS(s, s.add(v.normalize().mul(infR.value)), vec(sensor.value.x, -sensor.value.r), vec(sensor.value.x, sensor.value.r))
if (p) {
v = p.sub(s)
drawSegment(s, v, v.length())
Expand Down
78 changes: 50 additions & 28 deletions src/math.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,32 +126,64 @@ export class Vec {
// TODO: toString
}

const dot = (p: Vec, q: Vec) => {
return p.x * q.x + p.y * q.y
}

// export const dotAngle = (x1: number, y1: number, x2: number, y2: number) => {
// const norm1 = Math.sqrt(x1 * x1 + y1 * y1);
// const norm2 = Math.sqrt(x2 * x2 + y2 * y2);
// return Math.acos((x1 * x2 + y1 * y2) / (norm1 * norm2));
// };

const cross = (p: Vec, q: Vec) => {
return p.x * q.y - q.x * p.y
}

export const crossAngle = (p: Vec, q: Vec) => {
return Math.asin(cross(p, q) / (p.length() * q.length()));
};

//================================
// Support functions
// Geometry
//================================
// export const getIntersectionX = (px: number, py: number, theta: number, minX: number, maxX: number, y: number, maxR: number) => {
// const sin = Math.sin(theta);
// const cos = Math.cos(theta);
// const r = (y - py) / sin;
// const x = px + r * cos;
// if (r >= 0 && minX <= x && x <= maxX) {
// return [true, x, y, r];
// } else {
// return [false, px + maxR * cos, py + maxR * sin, maxR];
// }
// }

export const getIntersectionY = (s: Vec, v: Vec, x: number, minY: number, maxY: number) => {
const n = v.normalize()
const r = (x - s.x) / n.x;
const y = s.y + r * n.y;
if (r >= 0 && minY <= y && y <= maxY) {
return vec(x, y)
const eps = 1e-9

// ccw
const ccw = (a: Vec, b: Vec, c: Vec) => {
b = b.sub(a)
c = c.sub(a)
if (cross(b, c) > eps) return +1 // counter clockwise
if (cross(b, c) < -eps) return -1 // clockwise
if (dot(b, c) < 0) return +2 // cab (back)
if (b.length() < c.length()) return -2 // abc (front)
return 0 // acb (on segment)
}

const isIntersectedSS = (a1: Vec, a2: Vec, b1: Vec, b2: Vec) => {
return ccw(a1, a2, b1) * ccw(a1, a2, b2) <= 0 &&
ccw(b1, b2, a1) * ccw(b1, b2, a2) <= 0
}

const intersectionLL = (a1: Vec, a2: Vec, b1: Vec, b2: Vec) => {
const a = a2.sub(a1)
const b = b2.sub(b1)
return a1.add(a.mul(cross(b, b1.sub(a1))).div(cross(b, a)))
}

export const intersectionSS = (a1: Vec, a2: Vec, b1: Vec, b2: Vec) => {
if (isIntersectedSS(a1, a2, b1, b2)) {
return intersectionLL(a1, a2, b1, b2)
} else {
return null
}
}

//================================
// Support functions
//================================

export const getIntersectionLens = (s: Vec, v: Vec, cl: Vec, r: number /* lens diameter */, R: number /* lens curvature radius */, select: boolean) => {
const n = v.normalize()

Expand All @@ -175,16 +207,6 @@ export const getIntersectionLens = (s: Vec, v: Vec, cl: Vec, r: number /* lens d
}
}

// export const dotAngle = (x1: number, y1: number, x2: number, y2: number) => {
// const norm1 = Math.sqrt(x1 * x1 + y1 * y1);
// const norm2 = Math.sqrt(x2 * x2 + y2 * y2);
// return Math.acos((x1 * x2 + y1 * y2) / (norm1 * norm2));
// };

export const crossAngle = (p: Vec, q: Vec) => {
return Math.asin((p.x * q.y - q.x * p.y) / (p.length() * q.length()));
};

// const getIntersectionBody = (cx, cy, theta, maxR, isInner) => {
// // Front
// if (!isInner) {
Expand Down

0 comments on commit dd23854

Please sign in to comment.