I have a subclass of UIView
containing a bunch of graphics drawn using CGPAth
s. I need to know when a touch hits one of these paths, and which one.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches {
for p in myDrawnPaths {
if(p.contains(t.location(in: self)) {
doStuffWith(p)
}
}
}
}
Sometimes this code results in doStuffWith()
carried out on more than one path, including those far away from the hit location. I did some inspection and found out something really odd about the paths that shouldn't be affected:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches {
for p in myDrawnPaths {
print(p.contains(t.location(in: self))) //true
print(p.boundingBox.contains(t.location(in: self))) //false!
}
}
}
Huh? Shouldn't the bounding box contain the entire path, meaning that a point inside the path is guaranteed to be inside the bounding box?
The problem only arises in such tests -- when I use CoreGraphics API to draw and animate with the same CGPath
s, all the displays are correct.
UPDATE
I've tried to reproduce the issue with simple experimental paths in Playgrounds, but was unable to, so I had to take this from my actual app.
(75.0, 264.0) is in
Path 0x600003643960:
moveto (252.02, 287.067)
lineto (259.489, 286.324)
lineto (259.567, 286.754)
lineto (263.438, 286.167)
lineto (268.131, 285.503)
lineto (268.17, 285.268)
lineto (268.248, 284.681)
lineto (269.069, 283.235)
lineto (269.851, 282.57)
lineto (269.773, 280.576)
lineto (270.399, 279.95)
lineto (270.829, 279.833)
lineto (270.907, 278.425)
lineto (271.494, 277.252)
lineto (271.924, 277.486)
lineto (272.002, 277.721)
lineto (272.315, 277.799)
lineto (273.058, 277.408)
lineto (272.901, 273.85)
lineto (271.65, 270.643)
lineto (270.751, 267.085)
lineto (269.812, 265.834)
lineto (268.796, 265.13)
lineto (268.17, 265.56)
lineto (266.645, 266.264)
lineto (265.902, 268.219)
lineto (264.846, 269.666)
lineto (264.416, 269.9)
lineto (263.83, 269.666)
curveto (263.83, 269.666) (262.813, 269.079) (262.891, 268.845)
curveto (262.969, 268.61) (263.087, 266.889) (263.087, 266.889)
lineto (264.416, 266.381)
lineto (264.729, 265.052)
lineto (264.964, 264.035)
lineto (265.902, 263.409)
lineto (265.785, 259.499)
lineto (265.159, 258.6)
lineto (264.651, 258.287)
lineto (264.338, 257.466)
lineto (264.651, 257.153)
lineto (265.276, 257.27)
lineto (265.355, 256.644)
lineto (264.338, 255.784)
lineto (263.83, 254.767)
lineto (262.813, 254.767)
lineto (261.053, 254.181)
lineto (258.903, 252.851)
lineto (257.847, 252.851)
lineto (257.612, 253.086)
lineto (257.221, 252.891)
lineto (256.009, 251.991)
lineto (254.875, 252.695)
lineto (253.741, 253.594)
lineto (253.858, 255.002)
lineto (254.249, 255.119)
lineto (255.07, 255.315)
lineto (255.266, 255.628)
lineto (254.249, 255.941)
lineto (253.233, 256.058)
lineto (252.646, 256.762)
lineto (252.529, 257.583)
lineto (252.646, 258.209)
lineto (252.763, 260.359)
lineto (251.356, 261.18)
lineto (251.121, 261.102)
lineto (251.121, 259.46)
lineto (251.629, 258.521)
lineto (251.864, 257.583)
lineto (251.551, 257.27)
lineto (250.808, 257.583)
lineto (250.417, 259.225)
lineto (249.361, 259.655)
lineto (248.657, 260.398)
lineto (248.579, 260.789)
lineto (248.814, 261.102)
lineto (248.579, 262.119)
lineto (247.68, 262.314)
lineto (247.68, 262.745)
lineto (247.993, 263.683)
lineto (247.563, 266.068)
lineto (246.937, 267.632)
lineto (247.172, 269.47)
lineto (247.367, 269.9)
lineto (247.054, 270.839)
lineto (246.937, 271.152)
lineto (246.82, 272.208)
lineto (248.227, 274.554)
lineto (249.361, 277.095)
lineto (249.948, 278.972)
lineto (249.635, 280.81)
lineto (249.244, 283.156)
lineto (248.306, 285.19)
lineto (248.188, 286.246)
lineto (246.937, 287.458)
closepath
moveto (233.916, 259.147)
moveto (233.407, 258.717)
moveto (232.703, 254.65)
moveto (231.257, 254.142)
moveto (230.592, 253.242)
moveto (225.665, 252.148)
moveto (224.57, 251.717)
moveto (221.403, 250.857)
moveto (218.352, 250.466)
moveto (216.827, 248.394)
moveto (217.101, 248.198)
moveto (218.157, 247.885)
moveto (219.565, 246.986)
lineto (219.565, 246.595)
lineto (219.799, 246.36)
lineto (222.145, 245.969)
lineto (223.084, 245.226)
lineto (224.804, 244.405)
lineto (224.883, 243.897)
lineto (225.626, 242.763)
lineto (226.33, 242.45)
lineto (226.838, 241.746)
lineto (227.737, 240.847)
lineto (229.458, 239.908)
lineto (231.296, 239.713)
lineto (231.726, 240.143)
lineto (231.608, 240.534)
lineto (230.162, 240.925)
lineto (229.575, 242.137)
lineto (228.676, 242.45)
lineto (228.48, 243.388)
lineto (227.542, 244.64)
lineto (227.424, 245.656)
lineto (227.737, 245.852)
lineto (228.128, 245.422)
lineto (229.536, 244.288)
lineto (230.044, 244.796)
lineto (230.944, 244.796)
lineto (232.195, 245.187)
lineto (232.782, 245.617)
lineto (233.368, 246.83)
lineto (234.424, 247.885)
lineto (235.949, 247.807)
lineto (236.535, 247.416)
lineto (237.161, 247.924)
lineto (237.787, 248.12)
lineto (238.295, 247.807)
lineto (238.725, 247.807)
lineto (239.351, 247.416)
lineto (240.915, 246.008)
lineto (242.245, 245.578)
lineto (244.825, 245.461)
lineto (246.585, 244.718)
lineto (247.602, 244.21)
lineto (248.188, 244.288)
lineto (248.188, 246.517)
lineto (248.384, 246.634)
lineto (249.518, 246.947)
lineto (250.261, 246.751)
lineto (252.646, 246.126)
lineto (253.076, 245.696)
lineto (253.663, 245.891)
lineto (253.663, 248.628)
lineto (254.914, 249.84)
lineto (255.422, 250.075)
lineto (255.931, 250.466)
lineto (255.422, 250.583)
lineto (255.109, 250.466)
lineto (253.663, 250.271)
lineto (252.842, 250.505)
lineto (251.942, 250.427)
lineto (250.691, 251.014)
lineto (249.987, 251.014)
lineto (247.719, 250.505)
lineto (245.686, 250.583)
lineto (244.943, 251.6)
lineto (242.205, 251.835)
lineto (241.267, 252.148)
lineto (240.837, 253.36)
lineto (240.328, 253.79)
lineto (240.133, 253.712)
lineto (239.546, 253.086)
lineto (237.787, 254.025)
lineto (237.552, 254.025)
lineto (237.122, 253.399)
lineto (236.809, 253.477)
lineto (236.066, 255.198)
lineto (235.675, 256.762)
lineto (234.424, 259.46)
closepath
moveto (222.849, 237.367)
moveto (223.553, 236.545)
moveto (224.413, 236.233)
moveto (226.525, 234.708)
moveto (227.424, 234.473)
moveto (227.62, 234.668)
moveto (225.626, 236.663)
moveto (224.335, 237.406)
moveto (223.514, 237.758)
closepath
moveto (257.221, 250.31)
moveto (257.456, 251.287)
moveto (258.707, 251.365)
moveto (259.215, 250.896)
curveto (259.215, 250.896) (259.176, 250.31) (259.059, 250.271)
curveto (258.942, 250.192) (258.433, 249.528) (258.433, 249.528)
lineto (257.573, 249.606)
lineto (256.947, 249.684)
lineto (256.83, 250.114)
As we see, all the points in the path have the X-coordinate in the 200s, but a point with X-coordinate of 75 is computed to be within that path.
The issue goes away if I tack on a close
command to the path, but that brings up additional questions:
How does CGPath's
contains
work on open paths, and where, if anywhere, is it documented?Why does this affect the results of
contains
method and not anything I see on screen? For instance, if I tell the correspondingCALayer
to be filled with a certain color, the color doesn't spill out beyond where it should.