@@ -523,67 +523,128 @@ import Foundation
523523 }
524524 }
525525
526- open func split( standardizedRange range: PathComponentRange ) -> Self {
526+ open func split( standardizedRange range: PathComponentRange , bias : PathComponentBias ) -> Self {
527527 assert ( range. isStandardized)
528-
529528 guard !self . isPoint else { return self }
530529
531- let start = range. start
532- let end = range. end
533-
534- var resultPoints : [ CGPoint ] = [ ]
535- var resultOrders : [ Int ] = [ ]
536-
537- func appendElement( _ index: Int , _ start: CGFloat , _ end: CGFloat , includeStart: Bool , includeEnd: Bool ) {
530+ func splitElement( at index: Int , start: CGFloat , end: CGFloat , includeStart: Bool , includeEnd: Bool ) -> ( points: [ CGPoint ] , order: Int ) {
538531 assert ( includeStart || includeEnd)
539- let element = self . element ( at: index) . split ( from: start, to: end)
532+ let element = element ( at: index) . split ( from: start, to: end)
540533 let startIndex = includeStart ? 0 : 1
541534 let endIndex = includeEnd ? element. order : element. order - 1
542- resultPoints += element. points [ startIndex... endIndex]
543- resultOrders. append ( self . orders [ index] )
544- }
545-
546- if start. elementIndex == end. elementIndex {
547- // we just need to go from start.t to end.t
548- appendElement ( start. elementIndex, start. t, end. t, includeStart: true , includeEnd: true )
549- } else {
535+ return (
536+ points: Array ( element. points [ startIndex... endIndex] ) ,
537+ order: orders [ index]
538+ )
539+ }
540+
541+ func splitInner( start: IndexedPathComponentLocation , end: IndexedPathComponentLocation ) -> ( points: [ CGPoint ] , orders: [ Int ] ) {
542+ guard start. elementIndex != end. elementIndex else {
543+ // we just need to go from start.t to end.t
544+ let ( points, order) = splitElement ( at: start. elementIndex, start: start. t, end: end. t, includeStart: true , includeEnd: true )
545+ return ( points, [ order] )
546+ }
547+ var resultPoints : [ CGPoint ] = [ ]
548+ var resultOrders : [ Int ] = [ ]
549+
550550 // if end.t = 1, append from start.elementIndex+1 through end.elementIndex, otherwise to end.elementIndex
551- let lastFullElementIndex = end. t != 1.0 ? ( end. elementIndex- 1 ) : end. elementIndex
552- let firstFullElementIndex = start. t != 0.0 ? ( start. elementIndex+ 1 ) : start. elementIndex
551+ let lastElementIndex = end. t != 1.0 ? ( end. elementIndex- 1 ) : end. elementIndex
552+ let firstElementIndex = start. t != 0.0 ? ( start. elementIndex+ 1 ) : start. elementIndex
553+
553554 // if needed, append start.elementIndex from t=start.t to t=1
554- if firstFullElementIndex != start. elementIndex {
555- appendElement ( start. elementIndex, start. t, 1.0 , includeStart: true , includeEnd: false )
555+ if firstElementIndex != start. elementIndex {
556+ let ( points, order) = splitElement ( at: start. elementIndex, start: start. t, end: 1.0 , includeStart: true , includeEnd: false )
557+ resultPoints. append ( contentsOf: points)
558+ resultOrders. append ( order)
556559 }
557560 // if there exist full elements to copy, use the fast path to get them all in one fell swoop
558- let hasFullElements = firstFullElementIndex <= lastFullElementIndex
561+ let hasFullElements = firstElementIndex <= lastElementIndex
559562 if hasFullElements {
560- resultPoints += self . points [ self . offsets [ firstFullElementIndex] ... self . offsets [ lastFullElementIndex] + self . orders [ lastFullElementIndex] ]
561- resultOrders += self . orders [ firstFullElementIndex ... lastFullElementIndex]
563+ let points = points [ offsets [ firstElementIndex] ... offsets [ lastElementIndex] + orders[ lastElementIndex] ]
564+ let orders = orders [ firstElementIndex ... lastElementIndex]
565+ resultPoints. append ( contentsOf: points)
566+ resultOrders. append ( contentsOf: orders)
562567 }
563568 // if needed, append from end.elementIndex from t=0, to t=end.t
564- if lastFullElementIndex != end. elementIndex {
565- appendElement ( end. elementIndex, 0.0 , end. t, includeStart: !hasFullElements, includeEnd: true )
569+ if lastElementIndex != end. elementIndex {
570+ let ( points, order) = splitElement ( at: end. elementIndex, start: 0.0 , end: end. t, includeStart: !hasFullElements, includeEnd: true )
571+ resultPoints. append ( contentsOf: points)
572+ resultOrders. append ( order)
573+ }
574+ return ( points: resultPoints, orders: resultOrders)
575+ }
576+
577+ func splitOuter( start: IndexedPathComponentLocation , end: IndexedPathComponentLocation ) -> ( points: [ CGPoint ] , orders: [ Int ] ) {
578+ var resultPoints : [ CGPoint ] = [ ]
579+ var resultOrders : [ Int ] = [ ]
580+
581+ // if end.t = 0, append from end.elementIndex+1 through start.elementIndex-1, otherwise from end.elementIndex
582+ let lastElementIndex = end. t != 0.0 ? ( end. elementIndex+ 1 ) : end. elementIndex
583+ let firstElementIndex = start. t != 1.0 ? ( start. elementIndex- 1 ) : start. elementIndex
584+
585+ // if there exist full elements to copy, use the fast path to get them all in one fell swoop
586+ let hasFullElementsL = firstElementIndex > 0
587+ let hasFullElementsR = lastElementIndex < numberOfElements
588+
589+ if lastElementIndex != end. elementIndex { // right splitted curve
590+ let includeEndPoint = !( hasFullElementsR || hasFullElementsL)
591+ let ( points, order) = splitElement ( at: end. elementIndex, start: end. t, end: 1.0 , includeStart: true , includeEnd: includeEndPoint)
592+ resultPoints. append ( contentsOf: points)
593+ resultOrders. append ( order)
566594 }
595+ if hasFullElementsR {
596+ let points = points [ offsets [ lastElementIndex] ... offsets [ numberOfElements - 1 ] + orders[ numberOfElements - 1 ] ]
597+ let orders = orders [ lastElementIndex ..< numberOfElements]
598+ resultPoints. append ( contentsOf: points)
599+ resultOrders. append ( contentsOf: orders)
600+ }
601+ if hasFullElementsL {
602+ let points = points [ 0 ..< offsets [ firstElementIndex] + orders[ firstElementIndex] + ( hasFullElementsR ? 0 : 1 ) ]
603+ let orders = orders [ 0 ... firstElementIndex]
604+ resultPoints. append ( contentsOf: points)
605+ resultOrders. append ( contentsOf: orders)
606+ }
607+ if firstElementIndex != start. elementIndex { // left splitted curve
608+ let ( points, order) = splitElement ( at: start. elementIndex, start: 0.0 , end: start. t, includeStart: false , includeEnd: true )
609+ resultPoints. append ( contentsOf: points)
610+ resultOrders. append ( order)
611+ }
612+ return ( points: resultPoints, orders: resultOrders)
613+ }
614+
615+ switch bias {
616+ case . inner:
617+ let ( resultPoints, resultOrders) = splitInner (
618+ start: range. start,
619+ end: range. end
620+ )
621+ return type ( of: self ) . init ( points: resultPoints, orders: resultOrders)
622+
623+ case . outer:
624+ let ( resultPoints, resultOrders) = splitOuter (
625+ start: range. start,
626+ end: range. end
627+ )
628+ return type ( of: self ) . init ( points: resultPoints, orders: resultOrders)
567629 }
568- return type ( of: self ) . init ( points: resultPoints, orders: resultOrders)
569630 }
570631
571- public func split( range: PathComponentRange ) -> Self {
632+ public func split( range: PathComponentRange , bias : PathComponentBias ) -> Self {
572633 let reverse = range. end < range. start
573- let result = self . split ( standardizedRange: range. standardized)
634+ let result = self . split ( standardizedRange: range. standardized, bias : bias )
574635 return reverse ? result. reversed ( ) : result
575636 }
576637
577- public func split( from start: IndexedPathComponentLocation , to end: IndexedPathComponentLocation ) -> Self {
578- return self . split ( range: PathComponentRange ( from: start, to: end) )
638+ public func split( from start: IndexedPathComponentLocation , to end: IndexedPathComponentLocation , bias : PathComponentBias = . inner ) -> Self {
639+ return self . split ( range: PathComponentRange ( from: start, to: end) , bias : bias )
579640 }
580641
581642 open func reversed( ) -> Self {
582643 return type ( of: self ) . init ( points: self . points. reversed ( ) , orders: self . orders. reversed ( ) )
583644 }
584645
585646 open func copy( using t: CGAffineTransform ) -> Self {
586- return type ( of: self ) . init ( points: self . points. map { $0. applying ( t) } , orders: self . orders )
647+ return type ( of: self ) . init ( points: self . points. map { $0. applying ( t) } , orders: self . orders)
587648 }
588649}
589650
@@ -642,3 +703,8 @@ public struct PathComponentRange: Equatable {
642703 return PathComponentRange ( from: start, to: end)
643704 }
644705}
706+
707+ public enum PathComponentBias : Equatable {
708+ case inner
709+ case outer
710+ }
0 commit comments