@ -55,72 +55,72 @@ export function triangulate(originalGraph: Graph): Graph {
// For each vertex in the original graph, create a horizontal line that
// For each vertex in the original graph, create a horizontal line that
// extends in both directions until it intersects with either (1) the boundary
// extends in both directions until it intersects with either (1) the boundary
// or (2) a segment in the graph.
// or (2) a segment in the graph.
for ( const point of graph . points ) {
const originalPoints = [ . . . graph . points ]
for ( const point of originalPoints ) {
if ( boundary . isBoundaryPoint ( point ) ) continue // skip boundary points
if ( boundary . isBoundaryPoint ( point ) ) continue // skip boundary points
// Create the segment extending out to the left boundary
// First, check if there is a horizontal segment ending at this point
const leftPoint = Point . from ( leftBound . from . x , point . y )
// extending toward the left
let leftSegment = new Segment ( point , leftPoint )
const hasLeftHorizon = graph . getSegmentsEndingAt ( point )
. some ( segment = > segment . isHorizontal ( ) && segment . getOtherPoint ( point ) . isLeftOf ( point ) )
// Get segments that intersect with this
const leftIntersectingSegments = ( graph . segments
let leftmostPoint : Point = point
. map ( segment = > {
let rightmostPoint : Point = point
if ( boundary . isBoundarySegment ( segment ) ) {
let leftIntersectionRay : Segment
// Exclude boundary segments
let rightIntersectionRay : Segment
return undefined
}
if ( ! hasLeftHorizon ) {
const leftRaySegment = new Segment ( point , Point . from ( boundary . getLeftBoundary ( ) . xmin , point . y ) )
return {
const [ leftIntersectingSegment , leftIntersectingPoint ] = getFirstIntersectingSegmentInDirection (
segment ,
leftRaySegment ,
intersect : segment.getIntersectionWithin ( leftSegment ) ,
boundary ,
}
graph ,
} )
GraphDirection . LEFT
. filter ( group = > group && group . intersect ) as Array < { segment : Segment , intersect : Point } > )
)
. sort ( ( a , b ) = > {
return b . intersect . x - a . intersect . x // Sort by right-most x-value
leftmostPoint = leftIntersectingPoint
} )
leftIntersectionRay = leftIntersectingSegment
// Check if there was a nearer intersecting segment
const firstLeftIntersectingSegment = leftIntersectingSegments ? . [ 0 ] ? . segment
if ( firstLeftIntersectingSegment ) {
// Modify the leftSegment to end at the intersection point
const leftIntersect = graph . findExistingPointOrAdd ( leftIntersectingSegments [ 0 ] . intersect )
leftSegment = new Segment ( point , leftIntersect )
}
}
// Create the segment extending out to the right boundary
// First, check if there is a horizontal segment ending at this point
const rightPoint = Point . from ( rightBound . from . x , point . y )
// extending toward the left
let rightSegment = new Segment ( point , rightPoint )
const hasRightHorizon = graph . getSegmentsEndingAt ( point )
. some ( segment = > segment . isHorizontal ( ) && segment . getOtherPoint ( point ) . isRightOf ( point ) )
// Get segments that intersect with this
const rightIntersectingSegments = ( graph . segments
if ( ! hasRightHorizon ) {
. map ( segment = > {
const rightRaySegment = new Segment ( point , Point . from ( boundary . getRightBoundary ( ) . xmin , point . y ) )
if ( boundary . isBoundarySegment ( segment ) ) {
const [ rightIntersectingSegment , rightIntersectingPoint ] = getFirstIntersectingSegmentInDirection (
// Exclude boundary segments
rightRaySegment ,
return undefined
boundary ,
}
graph ,
GraphDirection . RIGHT
return {
)
segment ,
intersect : segment.getIntersectionWithin ( rightSegment ) ,
rightmostPoint = rightIntersectingPoint
}
rightIntersectionRay = rightIntersectingSegment
} )
. filter ( group = > group && group . intersect ) as Array < { segment : Segment , intersect : Point } > )
. sort ( ( a , b ) = > {
return a . intersect . x - b . intersect . x // Sort by left-most x-value
} )
// Check if there was a nearer intersecting segment
const firstRightIntersectingSegment = rightIntersectingSegments ? . [ 0 ] ? . segment
if ( firstRightIntersectingSegment ) {
// Modify the leftSegment to end at the intersection point
const rightIntersect = graph . findExistingPointOrAdd ( rightIntersectingSegments [ 0 ] . intersect )
rightSegment = new Segment ( point , rightIntersect )
}
}
const graphLeftSegment = graph . findExistingSegmentOrAdd ( leftSegment )
if ( ! leftmostPoint . is ( rightmostPoint ) ) {
const graphRightSegment = graph . findExistingSegmentOrAdd ( rightSegment )
// Check if this point has a line segment extending from both sides.
trapezoidSegments . push ( graphLeftSegment , graphRightSegment )
// If so, then the line segment will bisect a captive area to create 2 trapezoids,
// so we need to make 2 line segments.
let hasSegmentBelow = false
let hasSegmentAbove = false
graph . getSegmentsEndingAt ( point )
. forEach ( segment = > {
const otherPoint = segment . getOtherPoint ( point )
if ( otherPoint . y > point . y ) hasSegmentAbove = true
if ( otherPoint . y < point . y ) hasSegmentBelow = true
} )
if ( hasSegmentAbove && hasSegmentBelow ) {
trapezoidSegments . push ( graph . findExistingSegmentOrAdd ( new Segment ( leftmostPoint , point ) ) )
trapezoidSegments . push ( graph . findExistingSegmentOrAdd ( new Segment ( rightmostPoint , point ) ) )
} else {
trapezoidSegments . push ( graph . findExistingSegmentOrAdd ( new Segment ( leftmostPoint , rightmostPoint ) ) )
}
}
}
}
// Now, go through and identify trapezoids for all the horizontal segments we just added
// Now, go through and identify trapezoids for all the horizontal segments we just added
@ -154,6 +154,7 @@ export function triangulate(originalGraph: Graph): Graph {
GraphDirection . LEFT
GraphDirection . LEFT
)
)
console . log ( 'got leftIntersectSegment' , leftBoundaryHorizontalSegment . toQuickDisplay ( ) , leftIntersectSegment . toQuickDisplay ( ) , leftIntersectPoint . coordinate )
leftBoundaryHorizontalSegment = new Segment ( verticalMidpoint , leftIntersectPoint )
leftBoundaryHorizontalSegment = new Segment ( verticalMidpoint , leftIntersectPoint )
// Repeat to get the right boundary
// Repeat to get the right boundary
@ -196,21 +197,42 @@ export function triangulate(originalGraph: Graph): Graph {
// Let's find the segments that make up the trapezoid
// Let's find the segments that make up the trapezoid
// We will do this by re-creating segments for the four sides of the trapezoid
// We will do this by re-creating segments for the four sides of the trapezoid
// Split the left-side on the intersection point
// Split the left-side on the intersection point
let [ leftSegment1 , leftSegment2 ] = leftIntersectSegment . splitAt ( leftIntersectPoint ) // This is not right. Needs to be `segment`'s intersect point, not the midpoint intersect point
const leftSegmentIntersectPoint = leftIntersectSegment . getIntersectionWith ( segment )
graph . removeSegment ( leftIntersectSegment )
if ( ! leftSegmentIntersectPoint ) {
leftSegment1 = graph . findExistingSegmentOrAdd ( leftSegment1 )
console . log ( '!leftSegmentIntersectPoint' , segment . toQuickDisplay ( ) , leftIntersectSegment . toQuickDisplay ( ) )
leftSegment2 = graph . findExistingSegmentOrAdd ( leftSegment2 )
throw new Error ( 'Unable to find trapezoid segment intersection' )
}
// We care about the upper-segment from the split, as that is the bound of our trapezoid
// TODO Account for the case where we don't need to split the segment.
const trapezoidLeftBoundSegment = leftSegment1 . ymin === leftIntersectPoint . y ? leftSegment1 : leftSegment2
let trapezoidLeftBoundSegment = leftIntersectSegment
let leftSegment1 : Segment | undefined
let leftSegment2 : Segment | undefined
if ( ! leftIntersectSegment . hasPoint ( leftSegmentIntersectPoint ) ) {
let [ localLeftSegment1 , localLeftSegment2 ] = leftIntersectSegment . splitAt ( leftSegmentIntersectPoint )
graph . removeSegment ( leftIntersectSegment )
leftSegment1 = graph . findExistingSegmentOrAdd ( localLeftSegment1 )
leftSegment2 = graph . findExistingSegmentOrAdd ( localLeftSegment2 )
// We care about the upper-segment from the split, as that is the bound of our trapezoid
trapezoidLeftBoundSegment = leftSegment1 . ymin === leftSegmentIntersectPoint . y ? leftSegment1 : leftSegment2
}
// Repeat this process for the right-side segment
// Repeat this process for the right-side segment
let [ rightSegment1 , rightSegment2 ] = rightIntersectSegment . splitAt ( rightIntersectPoint )
const rightSegmentIntersectPoint = rightIntersectSegment . getIntersectionWith ( segment )
graph . removeSegment ( rightIntersectSegment )
if ( ! rightSegmentIntersectPoint ) throw new Error ( 'Unable to find trapezoid segment intersection' )
rightSegment1 = graph . findExistingSegmentOrAdd ( rightSegment1 )
rightSegment2 = graph . findExistingSegmentOrAdd ( rightSegment2 )
let trapezoidRightBoundSegment = rightIntersectSegment
let rightSegment1 : Segment | undefined
const trapezoidRightBoundSegment = rightSegment1 . ymin === rightBoundaryPoint . y ? leftSegment1 : leftSegment2
let rightSegment2 : Segment | undefined
if ( ! rightIntersectSegment . hasPoint ( rightSegmentIntersectPoint ) ) {
let [ localRightSegment1 , localRightSegment2 ] = rightIntersectSegment . splitAt ( rightSegmentIntersectPoint )
graph . removeSegment ( rightIntersectSegment )
rightSegment1 = graph . findExistingSegmentOrAdd ( localRightSegment1 )
rightSegment2 = graph . findExistingSegmentOrAdd ( localRightSegment2 )
// We care about the upper-segment from the split, as that is the bound of our trapezoid
trapezoidRightBoundSegment = rightSegment1 . ymin === rightSegmentIntersectPoint . y ? rightSegment1 : rightSegment2
}
// Now we have all 4 bounding segments. We find the bisector that creates
// Now we have all 4 bounding segments. We find the bisector that creates
// triangles with the largest minimum angle.
// triangles with the largest minimum angle.
@ -220,25 +242,25 @@ export function triangulate(originalGraph: Graph): Graph {
const upperRightPoint = graph . findExistingPointOrAdd ( Point . from ( upperIntersectSegment . xmax , upperIntersectSegment . ymax ) )
const upperRightPoint = graph . findExistingPointOrAdd ( Point . from ( upperIntersectSegment . xmax , upperIntersectSegment . ymax ) )
const bottomLeftBisectorSegment = new Segment ( lowerLeftPoint , upperRightPoint )
const bottomLeftBisectorSegment = new Segment ( lowerLeftPoint , upperRightPoint )
// const bottomLeftBisectorUpperTriangle = new Triangle([bottomLeftBisectorSegment, upperIntersectSegment, trapezoidLeftBoundSegment])
const bottomLeftBisectorUpperTriangle = new Triangle ( [ bottomLeftBisectorSegment , upperIntersectSegment , trapezoidLeftBoundSegment ] )
// const bottomLeftBisectorLowerTriangle = new Triangle([bottomLeftBisectorSegment, segment, trapezoidRightBoundSegment])
// const bottomLeftBisectorLowerTriangle = new Triangle([bottomLeftBisectorSegment, segment, trapezoidRightBoundSegment])
// const bottomLeftBisectorMinAngle = Math.min(bottomLeftBisectorUpperTriangle.getMinimumAngle(), bottomLeftBisectorLowerTriangle.getMinimumAngle())
// const bottomLeftBisectorMinAngle = Math.min(bottomLeftBisectorUpperTriangle.getMinimumAngle(), bottomLeftBisectorLowerTriangle.getMinimumAngle())
const upperLeftPoint = graph . findExistingPointOrAdd ( Point . from ( upperIntersectSegment . xmin , upperIntersectSegment . ymax ) )
// const upperLeftPoint = graph.findExistingPointOrAdd(Point.from(upperIntersectSegment.xmin, upperIntersectSegment.ymax))
const lowerRightPoint = graph . findExistingPointOrAdd ( Point . from ( segment . xmax , segment . ymin ) )
// const lowerRightPoint = graph.findExistingPointOrAdd(Point.from(segment.xmax, segment.ymin))
//
// const topRightBisectorSegment = new Segment(upperLeftPoint, lowerRightPoint)
// const topRightBisectorSegment = new Segment(upperLeftPoint, lowerRightPoint)
// const upperRightBisectorUpperTriangle = new Triangle([topRightBisectorSegment, upperIntersectSegment, trapezoidRightBoundSegment])
// const upperRightBisectorUpperTriangle = new Triangle([topRightBisectorSegment, upperIntersectSegment, trapezoidRightBoundSegment])
// const upperRightBisectorLowerTriangle = new Triangle([topRightBisectorSegment, trapezoidLeftBoundSegment, segment])
// const upperRightBisectorLowerTriangle = new Triangle([topRightBisectorSegment, trapezoidLeftBoundSegment, segment])
// const upperRightBisectorMinAngle = Math.min(upperRightBisectorUpperTriangle.getMinimumAngle(), upperRightBisectorLowerTriangle.getMinimumAngle())
// const upperRightBisectorMinAngle = Math.min(upperRightBisectorUpperTriangle.getMinimumAngle(), upperRightBisectorLowerTriangle.getMinimumAngle())
//
// const optimalBisectorUpperTriangle = upperRightBisectorMinAngle > bottomLeftBisectorMinAngle ? upperRightBisectorUpperTriangle : bottomLeftBisectorUpperTriangle
// const optimalBisectorUpperTriangle = upperRightBisectorMinAngle > bottomLeftBisectorMinAngle ? upperRightBisectorUpperTriangle : bottomLeftBisectorUpperTriangle
// const optimalBisectorLowerTriangle = upperRightBisectorMinAngle > bottomLeftBisectorMinAngle ? upperRightBisectorLowerTriangle : bottomLeftBisectorLowerTriangle
// const optimalBisectorLowerTriangle = upperRightBisectorMinAngle > bottomLeftBisectorMinAngle ? upperRightBisectorLowerTriangle : bottomLeftBisectorLowerTriangle
//
// Add the triangles to the graph
// // Add the triangles to the graph
// const upperTriangleSegments = optimalBisectorUpperTriangle.sides.map(side => graph.findExistingSegmentOrAdd(side))
// const upperTriangleSegments = optimalBisectorUpperTriangle.sides.map(side => graph.findExistingSegmentOrAdd(side))
// graph.findExistingTriangleOrAdd(new Triangle(upperTriangleSegments as [Segment, Segment, Segment]))
// graph.findExistingTriangleOrAdd(new Triangle(upperTriangleSegments as [Segment, Segment, Segment]))
//
// const lowerTriangleSegments = optimalBisectorLowerTriangle.sides.map(side => graph.findExistingSegmentOrAdd(side))
// const lowerTriangleSegments = optimalBisectorLowerTriangle.sides.map(side => graph.findExistingSegmentOrAdd(side))
// graph.findExistingTriangleOrAdd(new Triangle(lowerTriangleSegments as [Segment, Segment, Segment]))
// graph.findExistingTriangleOrAdd(new Triangle(lowerTriangleSegments as [Segment, Segment, Segment]))
}
}