-
Notifications
You must be signed in to change notification settings - Fork 350
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move
segmentsIntersect
to the math folder (#1399)
and add tests. There are some interesting edge cases! Issue: LEMS-2135 ## Test plan: `yarn test` Author: benchristel Reviewers: jeremywiebe, benchristel, SonicScrewdriver Required Reviewers: Approved By: jeremywiebe Checks: ✅ codecov/project, ✅ codecov/patch, ✅ Upload Coverage (ubuntu-latest, 20.x), ✅ Publish npm snapshot (ubuntu-latest, 20.x), ✅ Lint, Typecheck, Format, and Test (ubuntu-latest, 20.x), ✅ Cypress (ubuntu-latest, 20.x), ✅ Jest Coverage (ubuntu-latest, 20.x), ✅ Check builds for changes in size (ubuntu-latest, 20.x), ✅ Check for .changeset entries for all changed files (ubuntu-latest, 20.x), ✅ Publish Storybook to Chromatic (ubuntu-latest, 20.x), ✅ gerald Pull Request URL: #1399
- Loading branch information
1 parent
3108f93
commit 147ab04
Showing
5 changed files
with
209 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@khanacademy/perseus": patch | ||
--- | ||
|
||
Internal: refactor and test `segmentsIntersect` function |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
178 changes: 178 additions & 0 deletions
178
packages/perseus/src/widgets/interactive-graphs/math/geometry.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
import {segmentsIntersect} from "./geometry"; | ||
|
||
import type {Segment} from "./geometry"; | ||
|
||
describe("segmentsIntersect", () => { | ||
it("returns false when segments have zero length", () => { | ||
const segment1: Segment = [ | ||
[0, 0], | ||
[0, 0], | ||
]; | ||
const segment2: Segment = [ | ||
[1, 1], | ||
[1, 1], | ||
]; | ||
expect(segmentsIntersect(segment1, segment2)).toBe(false); | ||
}); | ||
|
||
it("returns false when segments are the same", () => { | ||
// intersecting segments must have a SINGLE intersection point. | ||
const segment1: Segment = [ | ||
[0, 0], | ||
[1, 1], | ||
]; | ||
const segment2: Segment = [ | ||
[0, 0], | ||
[1, 1], | ||
]; | ||
expect(segmentsIntersect(segment1, segment2)).toBe(false); | ||
}); | ||
|
||
it("returns false when an endpoint touches the other segment (lambda = 1)", () => { | ||
// We treat segments as open (exclusive of their endpoints). | ||
const segment1: Segment = [ | ||
[0, 0], | ||
[1, 1], | ||
]; | ||
const segment2: Segment = [ | ||
[0, 2], | ||
[2, 0], | ||
]; | ||
expect(segmentsIntersect(segment1, segment2)).toBe(false); | ||
}); | ||
|
||
it("returns false when an endpoint touches the other segment (lambda = 0)", () => { | ||
// We treat segments as open (exclusive of their endpoints). | ||
const segment1: Segment = [ | ||
[0, 0], | ||
[1, 1], | ||
]; | ||
const segment2: Segment = [ | ||
[-1, 1], | ||
[1, -1], | ||
]; | ||
expect(segmentsIntersect(segment1, segment2)).toBe(false); | ||
}); | ||
|
||
it("returns false when endpoints touch (gamma = 0)", () => { | ||
// We treat segments as open (exclusive of their endpoints). | ||
const segment1: Segment = [ | ||
[0, 0], | ||
[1, 1], | ||
]; | ||
const segment2: Segment = [ | ||
[2, 1], | ||
[1, 1], | ||
]; | ||
expect(segmentsIntersect(segment1, segment2)).toBe(false); | ||
}); | ||
|
||
it("returns false when endpoints touch (gamma = 1)", () => { | ||
// We treat segments as open (exclusive of their endpoints). | ||
const segment1: Segment = [ | ||
[0, 0], | ||
[1, 1], | ||
]; | ||
const segment2: Segment = [ | ||
[1, 1], | ||
[2, 1], | ||
]; | ||
expect(segmentsIntersect(segment1, segment2)).toBe(false); | ||
}); | ||
|
||
it("returns false given two horizontal segments", () => { | ||
const segment1: Segment = [ | ||
[0, 0], | ||
[1, 0], | ||
]; | ||
const segment2: Segment = [ | ||
[0, 1], | ||
[1, 1], | ||
]; | ||
expect(segmentsIntersect(segment1, segment2)).toBe(false); | ||
}); | ||
|
||
it("returns false given two vertical segments", () => { | ||
const segment1: Segment = [ | ||
[0, 0], | ||
[0, 1], | ||
]; | ||
const segment2: Segment = [ | ||
[1, 0], | ||
[1, 1], | ||
]; | ||
expect(segmentsIntersect(segment1, segment2)).toBe(false); | ||
}); | ||
|
||
it("returns false given two parallel diagonal segments", () => { | ||
const segment1: Segment = [ | ||
[0, 0], | ||
[1, 1], | ||
]; | ||
const segment2: Segment = [ | ||
[0, 1], | ||
[1, 2], | ||
]; | ||
expect(segmentsIntersect(segment1, segment2)).toBe(false); | ||
}); | ||
|
||
it("returns true given intersecting segments", () => { | ||
const segment1: Segment = [ | ||
[0, 0], | ||
[1, 1], | ||
]; | ||
const segment2: Segment = [ | ||
[1, 0], | ||
[0, 1], | ||
]; | ||
expect(segmentsIntersect(segment1, segment2)).toBe(true); | ||
}); | ||
|
||
it("returns false when segments are not parallel but do not intersect (lambda > 1)", () => { | ||
const segment1: Segment = [ | ||
[0, 0], | ||
[1, 1], | ||
]; | ||
const segment2: Segment = [ | ||
[9, 0], | ||
[0, 9], | ||
]; | ||
expect(segmentsIntersect(segment1, segment2)).toBe(false); | ||
}); | ||
|
||
it("returns false when segments are not parallel but do not intersect (lambda < 0)", () => { | ||
const segment1: Segment = [ | ||
[0, 0], | ||
[1, 1], | ||
]; | ||
const segment2: Segment = [ | ||
[-9, 0], | ||
[0, -9], | ||
]; | ||
expect(segmentsIntersect(segment1, segment2)).toBe(false); | ||
}); | ||
|
||
it("returns false when segments are not parallel but do not intersect (gamma > 1)", () => { | ||
const segment1: Segment = [ | ||
[-9, 0], | ||
[0, -9], | ||
]; | ||
const segment2: Segment = [ | ||
[0, 0], | ||
[1, 1], | ||
]; | ||
expect(segmentsIntersect(segment1, segment2)).toBe(false); | ||
}); | ||
|
||
it("returns false when segments are not parallel but do not intersect (gamma < 0)", () => { | ||
const segment1: Segment = [ | ||
[9, 0], | ||
[0, 9], | ||
]; | ||
const segment2: Segment = [ | ||
[0, 0], | ||
[1, 1], | ||
]; | ||
expect(segmentsIntersect(segment1, segment2)).toBe(false); | ||
}); | ||
}); |
21 changes: 21 additions & 0 deletions
21
packages/perseus/src/widgets/interactive-graphs/math/geometry.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import type {vec} from "mafs"; | ||
|
||
export type Segment = [vec.Vector2, vec.Vector2]; | ||
|
||
// Determines whether two line segments have exactly one intersection point. | ||
// The segments are treated as "open" - that is, not inclusive of their | ||
// endpoints. | ||
// Algorithm from https://stackoverflow.com/a/24392281/7347484 | ||
export const segmentsIntersect = ( | ||
[[a, b], [c, d]]: Segment, | ||
[[p, q], [r, s]]: Segment, | ||
): boolean => { | ||
const determinant = (c - a) * (s - q) - (r - p) * (d - b); | ||
if (determinant === 0) { | ||
return false; | ||
} else { | ||
const lambda = ((s - q) * (r - a) + (p - r) * (s - b)) / determinant; | ||
const gamma = ((b - d) * (r - a) + (c - a) * (s - b)) / determinant; | ||
return 0 < lambda && lambda < 1 && 0 < gamma && gamma < 1; | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters