import { List } from "./List" ; import { Epsilon } from "../Epsilon" ; import type { Point , Segment , XEvent , compare } from "../types" ; function eventCompare ( e1 , e2 ) { let comp = Epsilon . $pointsCompare ( e1 . pt , e2 . pt ) ; if ( comp !== 0 ) return comp ; if ( Epsilon . $pointsSame ( e1 . other . pt , e2 . other . pt ) ) return 0 ; if ( e1 . isStart !== e2 . isStart ) return e1 . isStart ? 1 : - 1 ; return Epsilon . $pointAboveOrOnLine ( e1 . other . pt , e2 . isStart ? e2 . pt : e2 . other . pt , e2 . isStart ? e2 . other . pt : e2 . pt ) ? 1 : - 1 ; } /**  IntersectionEvent 專用的  List export class EventList extends List { protected check ( ev , that ) { if ( that === ev ) return 0 ; return - eventCompare ( ev , that ) as compare ; } private add ( ev ) { this . findTransition ( ev ) . insert ( ev ) ; } public addSegment ( seg , primary ) { let ev_start = { isStart : true , pt : seg . start , seg , primary , status : null , } as XEvent ; let ev_end = { isStart : false , pt : seg . end , seg , primary , other : ev_start , status : null , } ; ev_start . other = ev_end ; this . add ( ev_start ) ; this . add ( ev_end ) ; return ev_start ; } private divide ( ev , pt ) { let new_segment = ev . seg . copy ( pt ) ; this . remove ( ev . other ) ; ev . seg . end = pt ; ev . other . pt = pt ; this . add ( ev . other ) ; return this . addSegment ( new_segment , ev . primary ) ; } public checkIntersection ( ev1 , ev2 ) { let seg1 = ev1 . seg ; let seg2 = ev2 . seg ; let a1 = seg1 . start ; let a2 = seg1 . end ; let b1 = seg2 . start ; let b2 = seg2 . end ; let i = Epsilon . $linesIntersect ( a1 , a2 , b1 , b2 ) ; if ( i === false ) { if ( ! Epsilon . $pointsCollinear ( a1 , a2 , b1 ) ) return false ; if ( Epsilon . $pointsSame ( a1 , b2 ) || Epsilon . $pointsSame ( a2 , b1 ) ) return false ; let a1_equ_b1 = Epsilon . $pointsSame ( a1 , b1 ) ; let a2_equ_b2 = Epsilon . $pointsSame ( a2 , b2 ) ; if ( a1_equ_b1 && a2_equ_b2 ) return ev2 ; let a1_between = ! a1_equ_b1 && Epsilon . $pointBetween ( a1 , b1 , b2 ) ; let a2_between = ! a2_equ_b2 && Epsilon . $pointBetween ( a2 , b1 , b2 ) ; if ( a1_equ_b1 ) { if ( a2_between ) { this . divide ( ev2 , a2 ) ; } else { this . divide ( ev1 , b2 ) ; } return ev2 ; } else if ( a1_between ) { if ( ! a2_equ_b2 ) { if ( a2_between ) { this . divide ( ev2 , a2 ) ; } else { this . divide ( ev1 , b2 ) ; } } this . divide ( ev2 , a1 ) ; } } else { if ( i . alongA === 0 ) { if ( i . alongB === - 1 ) this . divide ( ev1 , b1 ) ; else if ( i . alongB === 0 ) this . divide ( ev1 , i . pt ) ; else if ( i . alongB === 1 ) this . divide ( ev1 , b2 ) ; } if ( i . alongB === 0 ) { if ( i . alongA === - 1 ) this . divide ( ev2 , a1 ) ; else if ( i . alongA === 0 ) this . divide ( ev2 , i . pt ) ; else if ( i . alongA === 1 ) this . divide ( ev2 , a2 ) ; } } return false ; } public checkBothIntersections ( ev , above , below ) { if ( above ) { let eve = this . checkIntersection ( ev , above ) ; if ( eve ) return eve ; } if ( below ) return this . checkIntersection ( ev , below ) ; return false ; } }