swhitty / SwiftDraw

Compare 408b1f3 ... +0 ... a243b69

No flags found

Use flags to group coverage reports by test type, project and/or folders.
Then setup custom commit statuses and notifications for each flag.

e.g., #unittest #integration

#production #enterprise

#frontend #backend

Learn more about Codecov Flags here.


@@ -43,6 +43,11 @@
Loading
43 43
      case cubic(to: Point, control1: Point, control2: Point)
44 44
      case close
45 45
    }
46 +
47 +
    enum Direction {
48 +
      case clockwise
49 +
      case anticlockwise
50 +
    }
46 51
    
47 52
    func hash(into hasher: inout Hasher) {
48 53
      hasher.combine(self.segments)
@@ -125,3 +130,30 @@
Loading
125 130
        }
126 131
    }
127 132
}
133 +
134 +
135 +
extension BidirectionalCollection where Element == LayerTree.Path.Segment, Index == Int {
136 +
137 +
    // Determine direction by sign of calculated area
138 +
    // https://www.101computing.net/the-shoelace-algorithm/
139 +
    //
140 +
    var direction: LayerTree.Path.Direction {
141 +
        var lhs: LayerTree.Float = 0
142 +
        var rhs: LayerTree.Float = 0
143 +
        for (current, next) in compactMap(\.location).paired(with: .nextWrappingToFirst) {
144 +
            lhs += current.x * next.y
145 +
            rhs += current.y * next.x
146 +
        }
147 +
148 +
        return (lhs - rhs) < 0 ? .anticlockwise : .clockwise
149 +
    }
150 +
}
151 +
152 +
prefix func !(direction: LayerTree.Path.Direction) -> LayerTree.Path.Direction  {
153 +
    switch direction {
154 +
    case .clockwise:
155 +
        return .anticlockwise
156 +
    case .anticlockwise:
157 +
        return .clockwise
158 +
    }
159 +
}

@@ -0,0 +1,111 @@
Loading
1 +
//
2 +
//  PairedSequence.swift
3 +
//  SwiftDraw
4 +
//
5 +
//  Created by Simon Whitty on 6/8/22.
6 +
//  Copyright 2022 Simon Whitty
7 +
//
8 +
//  Distributed under the permissive zlib license
9 +
//  Get the latest version from here:
10 +
//
11 +
//  https://github.com/swhitty/SwiftDraw
12 +
//
13 +
//  This software is provided 'as-is', without any express or implied
14 +
//  warranty.  In no event will the authors be held liable for any damages
15 +
//  arising from the use of this software.
16 +
//
17 +
//  Permission is granted to anyone to use this software for any purpose,
18 +
//  including commercial applications, and to alter it and redistribute it
19 +
//  freely, subject to the following restrictions:
20 +
//
21 +
//  1. The origin of this software must not be misrepresented; you must not
22 +
//  claim that you wrote the original software. If you use this software
23 +
//  in a product, an acknowledgment in the product documentation would be
24 +
//  appreciated but is not required.
25 +
//
26 +
//  2. Altered source versions must be plainly marked as such, and must not be
27 +
//  misrepresented as being the original software.
28 +
//
29 +
//  3. This notice may not be removed or altered from any source distribution.
30 +
//
31 +
32 +
extension Sequence {
33 +
34 +
    // Iterate a sequence by including the next element each time.
35 +
    // A---B---C---D
36 +
    //
37 +
    // nextSkippingLast: (A,B)--(B,C)--(C,D)
38 +
    // nextWrappingToFirst: (A,B)--(B,C)--(C,D)--(D,A)
39 +
    func paired(with options: PairedSequence<Self>.Options = .nextWrappingToFirst) -> PairedSequence<Self> {
40 +
        PairedSequence(self, options: options)
41 +
    }
42 +
}
43 +
44 +
struct PairedSequence<S: Sequence>: Sequence {
45 +
    typealias Element = (S.Element, next: S.Element)
46 +
47 +
    enum Options {
48 +
        case nextSkippingLast
49 +
        case nextWrappingToFirst
50 +
    }
51 +
52 +
    init(_ inner: S, options: Options) {
53 +
        self.inner = inner
54 +
        self.options = options
55 +
    }
56 +
57 +
    private let inner: S
58 +
    private let options: Options
59 +
60 +
    func makeIterator() -> Iterator {
61 +
        return Iterator(inner.makeIterator(), options: options)
62 +
    }
63 +
64 +
    struct Iterator: IteratorProtocol {
65 +
        private var inner: S.Iterator
66 +
        private let options: Options
67 +
68 +
        init(_ inner: S.Iterator, options: Options) {
69 +
            self.inner = inner
70 +
            self.options = options
71 +
        }
72 +
73 +
        mutating func next() -> (S.Element, next: S.Element)? {
74 +
            guard !isComplete else { return  nil }
75 +
76 +
            guard let element = inner.next() else {
77 +
                isComplete = true
78 +
                return makeWrappedIfRequired()
79 +
            }
80 +
81 +
            if let previous = previous {
82 +
                self.previous = element
83 +
                return (previous, element)
84 +
            } else {
85 +
                first = element
86 +
                if let another = inner.next() {
87 +
                    self.previous = another
88 +
                    return (element, another)
89 +
                } else {
90 +
                    isComplete = true
91 +
                    return nil
92 +
                }
93 +
            }
94 +
        }
95 +
96 +
        private mutating func makeWrappedIfRequired() -> (S.Element, next: S.Element)? {
97 +
            guard options == .nextWrappingToFirst,
98 +
               let first = first,
99 +
               let previous = previous else {
100 +
                return nil
101 +
            }
102 +
            self.first = nil
103 +
            self.previous = nil
104 +
            return (previous, first)
105 +
        }
106 +
107 +
        private var isComplete: Bool = false
108 +
        private var first: S.Element?
109 +
        private var previous: S.Element?
110 +
    }
111 +
}

Learn more Showing 1 files with coverage changes found.

New file SwiftDraw/Utilities/PairedSequence.swift
New
Loading file...
Files Coverage
SwiftDraw 0.26% 76.30%
Project Totals (60 files) 76.30%
Loading