// Copyright (c) 2026 BigSaltyMan. BSL-1.0; see LICENSE.
// Clipper2-derived ring operations, Copyright (c) Angus Johnson 2010-2025.
///|
type OutPtId = Int
///|
type OutRecId = Int
///|
#warnings("-unused_value")
priv enum OutputSide {
Front
Back
} derive(Eq, Debug)
///|
priv struct OutputEnd {
record : OutRecId
side : OutputSide
}
///|
#warnings("-unused_value")
priv enum OutputStatus {
Building
Closed
Redirect(OutRecId)
Invalid
} derive(Eq, Debug)
///|
priv struct OutPt {
point : Point64
mut prev : OutPtId
mut next : OutPtId
mut record : OutRecId
mut alive : Bool
}
///|
priv struct OutRec {
mut anchor : OutPtId?
mut front_edge : EdgeId?
mut back_edge : EdgeId?
mut status : OutputStatus
split_from : OutRecId?
// Hints, final geometric parent, alias and split provenance are distinct.
mut owner_hint : OutRecId?
mut hint_inside : Bool
mut geometric_parent : OutRecId?
mut bounds_cache : (Int, Bounds64)?
mut revision : Int
}
///|
priv struct HorizontalSegment {
first : OutPtId
second : OutPtId
y : Int64
left : Int64
right : Int64
to_right : Bool
}
///|
priv struct HorizontalJoin {
first : OutPtId
second : OutPtId
left : Int64
right : Int64
mut consumed : Bool
opposed : Bool
}
///|
priv struct OutputState {
points : Array[OutPt]
records : Array[OutRec]
horizontals : Array[HorizontalSegment]
joins : Array[HorizontalJoin]
}
///|
fn new_output_state() -> OutputState {
{ points: [], records: [], horizontals: [], joins: [], }
}
///|
fn[T] output_error(state : ScanState, message : String) -> T raise ScanAbort {
scan_abort(state, InvalidInput(location(OutputTopology, None, None), message))
}
///|
fn output_spend(
state : ScanState,
nodes : Int,
work : Int,
loc? : ErrorLocation = location(OutputTopology, None, None),
) -> Unit raise ScanAbort {
if state.failure is Some(error) {
raise ScanAbort(error)
}
if state.cleaned {
output_error(state, "Output state has been cleaned")
}
if budget_error(state.budget, nodes, work, loc) is Some(error) {
scan_abort(state, error)
}
state.stats.nodes += nodes
state.stats.work += work
}
///|
fn output_point(state : ScanState, id : OutPtId) -> OutPt raise ScanAbort {
if state.failure is Some(error) {
raise ScanAbort(error)
}
if state.cleaned {
output_error(state, "Output state has been cleaned")
}
if id < 0 ||
id >= state.output.points.length() ||
!state.output.points[id].alive {
output_error(state, "Invalid or disposed output node")
}
state.output.points[id]
}
///|
fn output_resolve(state : ScanState, id : OutRecId) -> OutRecId raise ScanAbort {
let mut current = id
for steps = 0; steps <= state.output.records.length(); steps = steps + 1 {
output_spend(state, 0, 1)
if current < 0 || current >= state.output.records.length() {
output_error(state, "Invalid output record")
}
match state.output.records[current].status {
Redirect(target) => current = target
Invalid => output_error(state, "Disposed output record")
_ => return current
}
}
output_error(state, "Cyclic output redirection")
}
///|
fn output_new_record(
state : ScanState,
split_from : OutRecId?,
) -> OutRecId raise ScanAbort {
if split_from is Some(source) &&
(source < 0 || source >= state.output.records.length()) {
output_error(state, "Invalid split source record")
}
output_spend(state, 1, 1)
let id = state.output.records.length()
state.stats.output_records += 1
state.output.records.push({
anchor: None,
front_edge: None,
back_edge: None,
status: Building,
split_from,
owner_hint: match split_from {
Some(source) => state.output.records[source].owner_hint
None => None
},
hint_inside: false,
geometric_parent: None,
bounds_cache: None,
revision: 0,
})
id
}
///|
fn output_new_point(
state : ScanState,
record : OutRecId,
point : Point64,
) -> OutPtId raise ScanAbort {
output_spend(state, 1, 1)
let id = state.output.points.length()
state.stats.output_points += 1
state.output.points.push({ point, prev: id, next: id, record, alive: true, })
id
}
///|
/// Reserve record and initial node together before either container expands.
fn output_create(
state : ScanState,
point : Point64,
split_from? : OutRecId? = None,
) -> OutRecId raise ScanAbort {
scan_reserve(state, 2, 2, location(OutputTopology, None, None))
let record = output_new_record(state, split_from)
let node = output_new_point(state, record, point)
state.output.records[record].anchor = Some(node)
record
}
///|
fn output_append(
state : ScanState,
record : OutRecId,
side : OutputSide,
point : Point64,
) -> OutPtId raise ScanAbort {
let id = output_resolve(state, record)
let rec = state.output.records[id]
if rec.status != Building {
output_error(state, "Append requires a building contour")
}
let front = rec.anchor.unwrap()
let back = output_point(state, front).prev
let endpoint = if side == Front { front } else { back }
if output_point(state, endpoint).point == point {
return endpoint
}
let node = output_new_point(state, id, point)
state.output.points[node].prev = back
state.output.points[node].next = front
state.output.points[back].next = node
state.output.points[front].prev = node
if side == Front {
rec.anchor = Some(node)
}
rec.revision += 1
node
}
///|
fn output_bind(
state : ScanState,
edge_id : EdgeId,
record : OutRecId,
side : OutputSide,
) -> Unit raise ScanAbort {
let id = output_resolve(state, record)
let edge = edge_get(state, edge_id)
let rec = state.output.records[id]
if rec.status != Building || edge.output_end is Some(_) {
output_error(state, "Output end is already occupied or closed")
}
if (side == Front && rec.front_edge is Some(_)) ||
(side == Back && rec.back_edge is Some(_)) {
output_error(state, "Output side already has an active edge")
}
output_spend(state, 0, 1)
edge.output_end = Some({ record: id, side, })
if side == Front {
rec.front_edge = Some(edge_id)
} else {
rec.back_edge = Some(edge_id)
}
}
///|
fn output_unbind(state : ScanState, edge_id : EdgeId) -> Unit raise ScanAbort {
let edge = edge_get(state, edge_id)
if edge.output_end is Some(end) {
let id = output_resolve(state, end.record)
let rec = state.output.records[id]
if end.side == Front {
rec.front_edge = None
} else {
rec.back_edge = None
}
edge.output_end = None
}
}
///|
fn output_add_edge(
state : ScanState,
edge_id : EdgeId,
point : Point64,
) -> OutPtId? raise ScanAbort {
match edge_get(state, edge_id).output_end {
None => None
Some(end) => Some(output_append(state, end.record, end.side, point))
}
}
///|
fn output_start(
state : ScanState,
a : EdgeId,
b : EdgeId,
point : Point64,
split_from? : OutRecId? = None,
) -> Unit raise ScanAbort {
if a == b ||
edge_get(state, a).output_end is Some(_) ||
edge_get(state, b).output_end is Some(_) {
output_error(state, "Starting contour requires two distinct unbound edges")
}
let record = output_create(state, point, split_from~)
output_bind(state, a, record, Front)
output_bind(state, b, record, Back)
}
///|
fn output_exchange(
state : ScanState,
a : EdgeId,
b : EdgeId,
) -> Unit raise ScanAbort {
let ea = edge_get(state, a)
let eb = edge_get(state, b)
let x = ea.output_end
let y = eb.output_end
output_unbind(state, a)
output_unbind(state, b)
if x is Some(e) {
output_bind(state, b, e.record, e.side)
}
if y is Some(e) {
output_bind(state, a, e.record, e.side)
}
}
///|
fn output_ring(
state : ScanState,
anchor : OutPtId,
) -> Array[OutPtId] raise ScanAbort {
output_spend(state, 1, 0)
let result = []
let mut cursor = anchor
for steps = 0; steps <= state.output.points.length(); steps = steps + 1 {
let node = output_point(state, cursor)
output_spend(state, 1, 1)
result.push(cursor)
cursor = node.next
if cursor == anchor {
return result
}
}
output_error(state, "Output ring does not close at its anchor")
}
///|
fn output_close(state : ScanState, record : OutRecId) -> Unit raise ScanAbort {
let id = output_resolve(state, record)
let rec = state.output.records[id]
if rec.status != Building {
output_error(state, "Contour is not building")
}
if rec.front_edge is Some(a) {
output_unbind(state, a)
}
if rec.back_edge is Some(b) {
output_unbind(state, b)
}
output_spend(state, 0, 1)
rec.status = Closed
}
///|
/// Orient the open chains at the selected ends, then join their actual nodes.
fn output_close_or_merge(
state : ScanState,
a : EdgeId,
b : EdgeId,
point : Point64,
) -> Unit raise ScanAbort {
guard edge_get(state, a).output_end is Some(ae) else {
output_error(state, "Missing first output end")
}
guard edge_get(state, b).output_end is Some(be) else {
output_error(state, "Missing second output end")
}
let ar = output_resolve(state, ae.record)
let br = output_resolve(state, be.record)
let maximum = output_add_edge(state, a, point)
if !state.preserve_collinear {
ignore(output_add_edge(state, b, point))
}
if ar == br {
output_close(state, ar)
if state.preserve_collinear && maximum is Some(op) {
state.output.records[ar].anchor = Some(op)
}
return
}
let ac = state.output.records[ar]
let bc = state.output.records[br]
let left = output_ring(state, ac.anchor.unwrap())
let right = output_ring(state, bc.anchor.unwrap())
if ae.side == Front {
output_reverse(state, left)
}
if be.side == Back {
output_reverse(state, right)
}
let preserve_front = state.boolean_operation is Some(_) && ae.side == Front
if preserve_front {
output_reverse(state, left)
output_reverse(state, right)
}
let remaining_a = if ae.side == Front { ac.back_edge } else { ac.front_edge }
let remaining_b = if be.side == Front { bc.back_edge } else { bc.front_edge }
output_spend(state, 0, left.length() + right.length())
output_unbind(state, a)
output_unbind(state, b)
if remaining_a is Some(e) {
output_unbind(state, e)
}
if remaining_b is Some(e) {
output_unbind(state, e)
}
let first = left[0]
let last = right[right.length() - 1]
for i = 0; i < left.length(); i = i + 1 {
let n = state.output.points[left[i]]
n.prev = if i == 0 { last } else { left[i - 1] }
n.next = if i + 1 == left.length() { right[0] } else { left[i + 1] }
}
for i = 0; i < right.length(); i = i + 1 {
let n = state.output.points[right[i]]
n.record = ar
n.prev = if i == 0 { left[left.length() - 1] } else { right[i - 1] }
n.next = if i + 1 == right.length() { first } else { right[i + 1] }
}
ac.anchor = Some(if preserve_front { right[0] } else { first })
ac.revision += 1
bc.anchor = None
bc.status = Redirect(ar)
bc.revision += 1
if remaining_a is Some(e) {
output_bind(state, e, ar, if preserve_front { Back } else { Front })
}
if remaining_b is Some(e) {
output_bind(state, e, ar, if preserve_front { Front } else { Back })
}
}
///|
/// Swap successors: same closed record splits, different closed records merge.
/// Node identity, not coordinate equality, defines this explicit topology action.
fn output_splice(
state : ScanState,
first : OutPtId,
second : OutPtId,
) -> OutRecId raise ScanAbort {
if first == second {
output_error(state, "A splice requires distinct nodes")
}
let a = output_point(state, first)
let b = output_point(state, second)
let ar = output_resolve(state, a.record)
let br = output_resolve(state, b.record)
if state.output.records[ar].status != Closed ||
state.output.records[br].status != Closed {
output_error(state, "Ring splice requires completed contours")
}
let old_one = output_ring(state, first)
let total = if ar == br {
old_one.length()
} else {
old_one.length() + output_ring(state, second).length()
}
output_spend(state, 0, total + 1)
let new_record = if ar == br {
output_new_record(state, Some(ar))
} else {
ar
}
let an = a.next
let bn = b.next
a.next = bn
state.output.points[bn].prev = first
b.next = an
state.output.points[an].prev = second
// Traversals prepaid by the original disjoint rings; successor swap preserves
// exactly these nodes and cannot fail halfway through a topology mutation.
let mut cursor = first
for steps = 0; steps < total; steps = steps + 1 {
state.output.points[cursor].record = ar
cursor = state.output.points[cursor].next
if cursor == first {
break
}
}
state.output.records[ar].anchor = Some(first)
state.output.records[ar].revision += 1
if ar == br {
cursor = second
for steps = 0; steps < total; steps = steps + 1 {
state.output.points[cursor].record = new_record
cursor = state.output.points[cursor].next
if cursor == second {
break
}
}
state.output.records[new_record].anchor = Some(second)
state.output.records[new_record].status = Closed
} else {
state.output.records[br].anchor = None
state.output.records[br].status = Redirect(ar)
state.output.records[br].revision += 1
}
new_record
}
///|
fn output_remove_point(
state : ScanState,
record : OutRecId,
id : OutPtId,
) -> Unit raise ScanAbort {
let node = output_point(state, id)
output_spend(state, 0, 1)
let rec = state.output.records[record]
if node.next == id {
rec.anchor = None
rec.status = Invalid
} else {
state.output.points[node.prev].next = node.next
state.output.points[node.next].prev = node.prev
if rec.anchor == Some(id) {
rec.anchor = Some(node.next)
}
}
node.alive = false
rec.revision += 1
}
///|
/// PreserveCollinear matches the reference option. Always remove duplicates/spikes.
fn output_clean(
state : ScanState,
record : OutRecId,
preserve_collinear : Bool,
) -> Unit raise ScanAbort {
let id = output_resolve(state, record)
let rec = state.output.records[id]
if rec.status != Closed {
output_error(state, "Cleanup requires a completed ring")
}
let mut changed = true
while changed && rec.anchor is Some(anchor) {
changed = false
let nodes = output_ring(state, anchor)
if nodes.length() < 3 {
for n in nodes {
output_remove_point(state, id, n)
}
return
}
for n in nodes {
let node = output_point(state, n)
let prev = output_point(state, node.prev).point
let next = output_point(state, node.next).point
output_spend(state, 0, 1)
let collinear = cross_validated(prev, node.point, next) == 0L
let dot = (node.point.x - prev.x) * (next.x - node.point.x) +
(node.point.y - prev.y) * (next.y - node.point.y)
if collinear &&
(
node.point == prev ||
node.point == next ||
!preserve_collinear ||
dot < 0L
) {
output_remove_point(state, id, n)
changed = true
break
}
}
if !changed && nodes.length() == 3 {
let mut tiny = false
for n in nodes {
let a = state.output.points[n].point
let b = state.output.points[state.output.points[n].next].point
if a.x - b.x > -2L &&
a.x - b.x < 2L &&
a.y - b.y > -2L &&
a.y - b.y < 2L {
tiny = true
}
}
if tiny {
for n in nodes {
output_remove_point(state, id, n)
}
}
}
}
}
///|
#warnings("-unused_value")
fn output_extract(
state : ScanState,
preserve_collinear? : Bool = false,
) -> Paths64 raise ScanAbort {
let ids = output_finalize(state, preserve_collinear)
output_snapshot(state, ids)
}
///|
// Dynamic queue: repair may append records. No path or bounds is frozen until
// every original and newly split record has been cleaned and repaired.
fn output_finalize(
state : ScanState,
preserve_collinear : Bool,
) -> Array[OutRecId] raise ScanAbort {
for join in state.output.joins {
output_spend(state, 0, 1)
if !join.consumed {
output_error(
state, "Horizontal join still needs an explicit connection decision",
)
}
}
for id = 0; id < state.output.records.length(); id = id + 1 {
output_spend(state, 0, 1)
let rec = state.output.records[id]
rec.geometric_parent = None
rec.bounds_cache = None
if rec.status == Building {
output_error(state, "Cannot export an unfinished contour")
}
if rec.status == Closed {
output_clean(state, id, preserve_collinear)
if rec.status == Closed {
output_repair_local(state, id)
}
if rec.status == Closed {
output_clean(state, id, preserve_collinear)
}
}
}
output_spend(state, 1, state.output.records.length())
let ids = []
for id = 0; id < state.output.records.length(); id = id + 1 {
if state.output.records[id].status == Closed &&
state.output.records[id].anchor is Some(_) {
output_spend(state, 1, 0)
ids.push(id)
}
}
ids
}
///|
fn output_snapshot(
state : ScanState,
ids : Array[OutRecId],
) -> Paths64 raise ScanAbort {
output_spend(state, 1, 0)
let result = []
for id in ids {
let nodes = output_ring(state, state.output.records[id].anchor.unwrap())
output_spend(state, nodes.length() + 2, nodes.length())
result.push(nodes.map(fn(n) { state.output.points[n].point }))
}
result
}
///|
/// Bounded read-only diagnostics, including after resource failure.
#warnings("-unused_value")
fn output_invariants(
state : ScanState,
metered? : Bool = false,
) -> Result[Unit, String] {
let out = state.output
match validation_charge(state, metered, out.points.length() + 1, 0) {
Ok(_) => ()
Err(e) => return Err(e)
}
let seen = Array::make(out.points.length(), false)
for id = 0; id < out.records.length(); id = id + 1 {
match validation_charge(state, metered, 0, 1) {
Ok(_) => ()
Err(e) => return Err(e)
}
let rec = out.records[id]
if rec.revision < 0 {
return Err("Invalid topology revision")
}
let mut root = id
let mut steps = 0
while out.records[root].status is Redirect(next) {
match validation_charge(state, metered, 0, 1) {
Ok(_) => ()
Err(e) => return Err(e)
}
if next < 0 ||
next >= out.records.length() ||
steps >= out.records.length() {
return Err("Invalid or cyclic redirection")
}
root = next
steps += 1
}
if rec.status is Redirect(_) || rec.status == Invalid {
if rec.anchor is Some(_) ||
rec.front_edge is Some(_) ||
rec.back_edge is Some(_) {
return Err("Inactive record retains references")
}
continue
}
guard rec.anchor is Some(anchor) else {
return Err("Missing output anchor")
}
let mut cursor = anchor
for count = 0; count <= out.points.length(); count = count + 1 {
match validation_charge(state, metered, 0, 1) {
Ok(_) => ()
Err(e) => return Err(e)
}
if cursor < 0 || cursor >= out.points.length() {
return Err("Invalid output node")
}
let n = out.points[cursor]
if !n.alive || n.record != id || seen[cursor] {
return Err("Wrong output ownership or overlapping rings")
}
seen[cursor] = true
if n.next < 0 ||
n.next >= out.points.length() ||
n.prev < 0 ||
n.prev >= out.points.length() {
return Err("Invalid output link")
}
if out.points[n.next].prev != cursor || out.points[n.prev].next != cursor {
return Err("Broken output reciprocal links")
}
cursor = n.next
if cursor == anchor {
break
}
if count == out.points.length() {
return Err("Output cycle misses anchor")
}
}
if rec.status == Closed &&
(rec.front_edge is Some(_) || rec.back_edge is Some(_)) {
return Err("Closed record retains active ends")
}
match validation_charge(state, metered, 3, 0) {
Ok(_) => ()
Err(e) => return Err(e)
}
for (handle, side) in [(rec.front_edge, Front), (rec.back_edge, Back)] {
match validation_charge(state, metered, 0, 1) {
Ok(_) => ()
Err(e) => return Err(e)
}
if handle is Some(e) {
guard edge_peek(state, e) is Some(edge) else {
return Err("Stale output edge")
}
guard edge.output_end is Some(end) else {
return Err("Missing output end")
}
if end.record != id || end.side != side {
return Err("Output end mismatch")
}
}
}
if rec.split_from is Some(source) && (source < 0 || source >= id) {
return Err("Invalid split provenance")
}
}
for i = 0; i < out.points.length(); i = i + 1 {
match validation_charge(state, metered, 0, 1) {
Ok(_) => ()
Err(e) => return Err(e)
}
if out.points[i].alive != seen[i] {
return Err("Orphan output point")
}
}
for slot in state.slots {
match validation_charge(state, metered, 0, 1) {
Ok(_) => ()
Err(e) => return Err(e)
}
if slot.edge is Some(edge) && edge.output_end is Some(end) {
if end.record < 0 || end.record >= out.records.length() {
return Err("Invalid active output record")
}
let rec = out.records[end.record]
let handle = if end.side == Front {
rec.front_edge
} else {
rec.back_edge
}
guard handle is Some(id) else {
return Err("Unregistered active output end")
}
guard edge_peek(state, id) is Some(other) else {
return Err("Stale active output end")
}
if other.chain != edge.chain {
return Err("Wrong active output end")
}
}
}
Ok(())
}
///|
fn output_reverse(
state : ScanState,
nodes : Array[OutPtId],
) -> Unit raise ScanAbort {
for i = 0; i < nodes.length() / 2; i = i + 1 {
output_spend(state, 0, 1)
let j = nodes.length() - 1 - i
let tmp = nodes[i]
nodes[i] = nodes[j]
nodes[j] = tmp
}
}
///|
fn output_endpoint(
state : ScanState,
edge : EdgeId,
) -> OutPtId? raise ScanAbort {
match edge_get(state, edge).output_end {
None => None
Some(end) => {
let rec = state.output.records[output_resolve(state, end.record)]
let front = rec.anchor.unwrap()
Some(
if end.side == Front {
front
} else {
output_point(state, front).prev
},
)
}
}
}
///|
fn strict_segment_cross(
a : Point64,
b : Point64,
c : Point64,
d : Point64,
) -> Bool {
let ac = cross_validated(a, b, c)
let ad = cross_validated(a, b, d)
let ca = cross_validated(c, d, a)
let cb = cross_validated(c, d, b)
ac != 0L &&
ad != 0L &&
ca != 0L &&
cb != 0L &&
(ac > 0L) != (ad > 0L) &&
(ca > 0L) != (cb > 0L)
}
///|
fn output_area2(
state : ScanState,
nodes : Array[OutPtId],
) -> BigInt raise ScanAbort {
let mut sum = Small(0L)
for id in nodes {
output_spend(state, 0, 1)
let n = state.output.points[id]
let p = state.output.points[n.prev].point
sum = add_area_term(sum, p.x * n.point.y - p.y * n.point.x)
}
exact_area(sum)
}
///|
/// Fixed FixSelfIntersects local four-edge repair, including the micro-crossing
/// duplicate branch. Area thresholds use exact integers with explicit scaling:
/// upstream Area = S/2, upstream AreaTriangle = T (twice triangle area).
fn output_repair_local(
state : ScanState,
record : OutRecId,
) -> Unit raise ScanAbort {
let rec = state.output.records[record]
let mut again = true
while again && rec.status == Closed {
again = false
let nodes = output_ring(state, rec.anchor.unwrap())
if nodes.length() < 4 {
return
}
for id in nodes {
output_spend(state, 0, 1)
let node = state.output.points[id]
let prev = state.output.points[node.prev]
let next = state.output.points[node.next]
let far = state.output.points[next.next]
if !strict_segment_cross(prev.point, node.point, next.point, far.point) {
continue
}
let fifth = state.output.points[far.next]
if strict_segment_cross(prev.point, node.point, far.point, fifth.point) {
// Duplicate before op with the fifth coordinate, as fixed upstream.
let extra = output_new_point(state, record, fifth.point)
state.output.points[extra].prev = node.prev
state.output.points[extra].next = id
prev.next = extra
node.prev = extra
rec.revision += 1
again = true
break
}
let sum = output_area2(state, nodes)
let absolute = if sum < 0N { -sum } else { sum }
if absolute < 4N {
for n in nodes {
output_remove_point(state, record, n)
}
return
}
let point = match
line_intersection(prev.point, node.point, next.point, far.point) {
Some(p) => p
None =>
output_error(
state, "Local self-crossing has no numerical intersection",
)
}
let triangle = BigInt::from_int64(
cross_validated(point, node.point, next.point),
)
let abs_triangle = if triangle < 0N { -triangle } else { triangle }
let keep_triangle = abs_triangle >= 1N &&
(abs_triangle * 2N > absolute || (triangle > 0N) == (sum > 0N))
let insert_main = point != prev.point && point != far.point
let needed = (if insert_main { 1 } else { 0 }) +
(if keep_triangle { 2 } else { 0 })
// Preflight all related record/node allocations and mutation work together.
if needed > state.budget.limits.max_nodes - state.budget.stats.nodes {
scan_abort(
state,
ResourceLimitExceeded(
location(OutputTopology, None, None),
InternalNodes,
state.limits.max_nodes,
),
)
}
if needed + 1 > state.budget.limits.max_work - state.budget.stats.work {
scan_abort(
state,
ResourceLimitExceeded(
location(OutputTopology, None, None),
ScanWork,
state.limits.max_work,
),
)
}
output_spend(state, 0, 1)
let saved_prev = node.prev
let saved_next = node.next
let saved_far = next.next
let main_node = if insert_main {
Some(output_new_point(state, record, point))
} else {
None
}
let new_rec = if keep_triangle {
Some(output_new_record(state, Some(record)))
} else {
None
}
let triangle_node = match new_rec {
Some(r) => Some(output_new_point(state, r, point))
None => None
}
match main_node {
Some(n) => {
state.output.points[n].prev = saved_prev
state.output.points[n].next = saved_far
prev.next = n
far.prev = n
}
None => {
prev.next = saved_far
far.prev = saved_prev
}
}
rec.anchor = Some(saved_prev)
rec.revision += 1
match (new_rec, triangle_node) {
(Some(r), Some(n)) => {
node.record = r
next.record = r
node.prev = n
next.next = n
state.output.points[n].prev = saved_next
state.output.points[n].next = id
state.output.records[r].anchor = Some(n)
state.output.records[r].status = Closed
}
_ => {
node.alive = false
next.alive = false
}
}
again = true
break
}
}
}