Skip to content

Commit

Permalink
add precision
Browse files Browse the repository at this point in the history
  • Loading branch information
NailxSharipov committed Aug 26, 2024
1 parent ac5b2ef commit 88beef9
Show file tree
Hide file tree
Showing 12 changed files with 1,844 additions and 48 deletions.
23 changes: 21 additions & 2 deletions Sources/iOverlay/Core/Solver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,25 @@ public enum Strategy {
case auto
}

public enum Precision {
case absolute
case average
case auto
}

public struct Solver {

public static let list = Solver(strategy: .list)
public static let tree = Solver(strategy: .tree)
public static let auto = Solver(strategy: .auto)

public let strategy: Strategy
private static let maxListCount: Int = 1024
public let precision: Precision
private static let maxListCount: Int = 2048

init(strategy: Strategy) {
init(strategy: Strategy, precision: Precision = .auto) {
self.strategy = strategy
self.precision = precision
}

func isList(edges: [Segment]) -> Bool {
Expand All @@ -44,4 +52,15 @@ public struct Solver {
}
}

func radius(iteration: Int) -> Int64 {
switch self.precision {
case .absolute:
return 0
case .average:
return 2
case .auto:
return Int64(1 << min(2, iteration))
}
}

}
8 changes: 4 additions & 4 deletions Sources/iOverlay/Split/CrossSolver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ enum CrossType {

struct CrossSolver {

static func cross(target: XSegment, other: XSegment) -> CrossResult? {
static func cross(target: XSegment, other: XSegment, radius: Int64) -> CrossResult? {

// by this time segments already at intersection range by x

Expand All @@ -76,7 +76,7 @@ struct CrossSolver {
}

if s == 0 {
return Self.middleCross(target: target, other: other)
return Self.middleCross(target: target, other: other, radius: radius)
}

// end cross
Expand Down Expand Up @@ -129,7 +129,7 @@ struct CrossSolver {
return OverlayMask(isTargetA: isTargetA, isTargetB: isTargetB, isOtherA: isOtherA, isOtherB: isOtherB)
}

private static func middleCross(target: XSegment, other: XSegment) -> CrossResult {
private static func middleCross(target: XSegment, other: XSegment, radius: Int64) -> CrossResult {
let p = Self.crossPoint(target: target, other: other)

if Triangle.isLine(p0: target.a, p1: p, p2: target.b) && Triangle.isLine(p0: other.a, p1: p, p2: other.b) {
Expand All @@ -145,7 +145,7 @@ struct CrossSolver {
let ra1 = other.a.sqrDistance(p)
let rb1 = other.b.sqrDistance(p)

if ra0 <= 2 || ra1 <= 2 || rb0 <= 2 || rb1 <= 2 {
if ra0 <= radius || ra1 <= radius || rb0 <= radius || rb1 <= radius {
let r0 = min(ra0, rb0)
let r1 = min(ra1, rb1)

Expand Down
10 changes: 7 additions & 3 deletions Sources/iOverlay/Split/SegmentTree.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ struct SegmentTree {

private let power: Int
fileprivate var nodes: [IntervalNode]
var radius: Int64

private static func createNodes(range: LineRange, power: Int) -> [IntervalNode] {
let n = 1 << power
Expand Down Expand Up @@ -76,9 +77,10 @@ struct SegmentTree {
return nodes
}

init(range: LineRange, power: Int) {
init(range: LineRange, power: Int, radius: Int64) {
self.power = power
self.nodes = Self.createNodes(range: range, power: power)
self.radius = radius
}

mutating func insert(fragment: Fragment) {
Expand Down Expand Up @@ -307,15 +309,17 @@ struct SegmentTree {
j: scan.index,
ei: this.xSegment,
ej: scan.xSegment,
marks: &marks
marks: &marks,
radius: self.radius
)
} else {
isRound = SplitSolver.cross(
i: scan.index,
j: this.index,
ei: scan.xSegment,
ej: this.xSegment,
marks: &marks
marks: &marks,
radius: self.radius
)
}

Expand Down
21 changes: 9 additions & 12 deletions Sources/iOverlay/Split/SplitSolver+List.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,19 @@ extension SplitSolver {
func listSplit(edges: inout [Segment]) -> Bool {
var marks = [LineMark]()
var needToFix = true
var iter = 0

while needToFix {
while needToFix && edges.count > 2 {
needToFix = false

marks.removeAll(keepingCapacity: true)

let n = edges.count
let radius = self.solver.radius(iteration: iter)

guard n > 2 else {
return true
}

for i in 0..<n - 1 {
for i in 0..<edges.count - 1 {
let ei = edges[i].xSegment
let ri = ei.boundary
for j in i + 1..<n {
for j in i + 1..<edges.count {
let ej = edges[j].xSegment
if ei.b.x < ej.a.x {
break
Expand All @@ -37,7 +34,7 @@ extension SplitSolver {
continue
}

let isRound = Self.cross(i: i, j: j, ei: ei, ej: ej, marks: &marks)
let isRound = Self.cross(i: i, j: j, ei: ei, ej: ej, marks: &marks, radius: radius)
needToFix = needToFix || isRound
}
}
Expand All @@ -47,13 +44,13 @@ extension SplitSolver {
}

Self.apply(marks: &marks, edges: &edges)

guard n > 0 else { return true }


if !solver.isList(edges: edges) {
// finish with tree solver if edges is become large
return self.treeSplit(edges: &edges)
}

iter += 1
}

return true
Expand Down
32 changes: 21 additions & 11 deletions Sources/iOverlay/Split/SplitSolver+Tree.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,17 @@ extension SplitSolver {
}

private func simple(verRange: LineRange, layout: SpaceLayout, edges: inout [Segment]) {
var tree = SegmentTree(range: verRange, power: layout.power)
var tree = SegmentTree(range: verRange, power: layout.power, radius: 0)

var marks = [LineMark]()

var needToFix = true
var iter = 0

while needToFix {
while needToFix && edges.count > 2 {
needToFix = false

marks.removeAll(keepingCapacity: true)
tree.radius = self.solver.radius(iteration: iter)

for i in 0..<edges.count {
let fragment = Fragment(index: i, xSegment: edges[i].xSegment)
Expand All @@ -53,22 +54,25 @@ extension SplitSolver {
tree.clear()

SplitSolver.apply(marks: &marks, edges: &edges)

marks.removeAll(keepingCapacity: true)

iter += 1
}
}

private func complex(verRange: LineRange, layout: SpaceLayout, edges: inout [Segment]) {
var tree = SegmentTree(range: verRange, power: layout.power)
var tree = SegmentTree(range: verRange, power: layout.power, radius: 0)

var marks = [LineMark]()
var needToFix = true
var fragments = [Fragment]()
fragments.reserveCapacity(2 * edges.count)

while needToFix {

var iter = 0

while needToFix && edges.count > 2 {
needToFix = false

marks.removeAll(keepingCapacity: true)
fragments.removeAll(keepingCapacity: true)

for i in 0..<edges.count {
layout.breakIntoFragments(index: i, xSegment: edges[i].xSegment, buffer: &fragments)
Expand All @@ -80,6 +84,7 @@ extension SplitSolver {
return
}

tree.radius = self.solver.radius(iteration: iter)

for fragment in fragments {
let anyRound = tree.intersect(this: fragment, marks: &marks)
Expand All @@ -91,10 +96,15 @@ extension SplitSolver {
guard !marks.isEmpty else {
return
}


fragments.removeAll(keepingCapacity: true)
tree.clear()

SplitSolver.apply(marks: &marks, edges: &edges)

marks.removeAll(keepingCapacity: true)

iter += 1
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/iOverlay/Split/SplitSolver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ struct SplitSolver {
}
}

static func cross(i: Int, j: Int, ei: XSegment, ej: XSegment, marks: inout[LineMark]) -> Bool {
guard let cross = CrossSolver.cross(target: ei, other: ej) else {
static func cross(i: Int, j: Int, ei: XSegment, ej: XSegment, marks: inout[LineMark], radius: Int64) -> Bool {
guard let cross = CrossSolver.cross(target: ei, other: ej, radius: radius) else {
return false
}

Expand Down
16 changes: 8 additions & 8 deletions Tests/iOverlayTests/IntervalTreeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ final class IntervalTreeTests: XCTestCase {
}

func test_02() throws {
var tree = SegmentTree(range: LineRange(min: 0, max: 128), power: 3)
var tree = SegmentTree(range: LineRange(min: 0, max: 128), power: 3, radius: 2)
let xSeg = XSegment(a: Point(0, 1), b: Point(0, 127))
tree.insert(fragment: Fragment(index: 0, xSegment: xSeg))

Expand Down Expand Up @@ -52,7 +52,7 @@ final class IntervalTreeTests: XCTestCase {
}

func test_03() throws {
var tree = SegmentTree(range: LineRange(min: 0, max: 128), power: 3)
var tree = SegmentTree(range: LineRange(min: 0, max: 128), power: 3, radius: 2)
let xSeg = XSegment(a: Point(0, 16), b: Point(0, 112))
tree.insert(fragment: Fragment(index: 0, xSegment: xSeg))

Expand Down Expand Up @@ -81,7 +81,7 @@ final class IntervalTreeTests: XCTestCase {
}

func test_04() throws {
var tree = SegmentTree(range: LineRange(min: 0, max: 128), power: 3)
var tree = SegmentTree(range: LineRange(min: 0, max: 128), power: 3, radius: 2)
let xSeg = XSegment(a: Point(0, 17), b: Point(0, 111))
tree.insert(fragment: Fragment(index: 0, xSegment: xSeg))

Expand Down Expand Up @@ -110,7 +110,7 @@ final class IntervalTreeTests: XCTestCase {
}

func test_05() throws {
var tree = SegmentTree(range: LineRange(min: 0, max: 128), power: 3)
var tree = SegmentTree(range: LineRange(min: 0, max: 128), power: 3, radius: 2)
let xSeg = XSegment(a: Point(0, 32), b: Point(0, 96))
tree.insert(fragment: Fragment(index: 0, xSegment: xSeg))

Expand Down Expand Up @@ -139,7 +139,7 @@ final class IntervalTreeTests: XCTestCase {
}

func test_06() throws {
var tree = SegmentTree(range: LineRange(min: 0, max: 128), power: 3)
var tree = SegmentTree(range: LineRange(min: 0, max: 128), power: 3, radius: 2)
let xSeg = XSegment(a: Point(0, 33), b: Point(0, 95))
tree.insert(fragment: Fragment(index: 0, xSegment: xSeg))

Expand Down Expand Up @@ -167,7 +167,7 @@ final class IntervalTreeTests: XCTestCase {
}

func test_07() throws {
var tree = SegmentTree(range: LineRange(min: -8, max: 9), power: 3)
var tree = SegmentTree(range: LineRange(min: -8, max: 9), power: 3, radius: 2)
let a0 = Point(0, -6)
let b0 = Point(8, 0)
let a1 = Point(0, 3)
Expand All @@ -189,14 +189,14 @@ final class IntervalTreeTests: XCTestCase {

let range = LineRange(min: -28, max: 28)
let layout = SpaceLayout(height: Int(range.width), count: 16)
var tree = SegmentTree(range: range, power: layout.power)
var tree = SegmentTree(range: range, power: layout.power, radius: 2)
tree.insert(fragment: Fragment(index: 0, xSegment: s0))

var marks = [LineMark]()

_ = tree.intersect(this: Fragment(index: 0, xSegment: s1), marks: &marks)

let r1 = CrossSolver.cross(target: s0, other: s1)
let r1 = CrossSolver.cross(target: s0, other: s1, radius: 2)

XCTAssertFalse(marks.isEmpty)
XCTAssertNotNil(r1)
Expand Down
Loading

0 comments on commit 88beef9

Please sign in to comment.