0

image

Problem Image

I want to find out all the cgpoints which comes under the path of UIBezierPath for this i have 3 points by which I am creating the UIBezier path. I have tried below code but it is not providing the accurate results. Please check the attached image Could any body help me out on this.

Thanks in advance:)

  func getPathElementsPointsAndTypes() -> ([CGPoint],[CGPathElementType]) {
    var arrayPoints : [CGPoint]! = [CGPoint]()
    var arrayTypes : [CGPathElementType]! = [CGPathElementType]()
    self.forEach { element in
        switch (element.type) {
        case CGPathElementType.moveToPoint:
            arrayPoints.append(element.points[0])
            arrayTypes.append(element.type)
        case .addLineToPoint:
            arrayPoints.append(element.points[0])
            arrayTypes.append(element.type)
        case .addQuadCurveToPoint:
            arrayPoints.append(element.points[0])
            arrayPoints.append(element.points[1])
            arrayTypes.append(element.type)
            arrayTypes.append(element.type)
        case .addCurveToPoint:
            arrayPoints.append(element.points[0])
            arrayPoints.append(element.points[1])
            arrayPoints.append(element.points[2])
            arrayTypes.append(element.type)
            arrayTypes.append(element.type)
            arrayTypes.append(element.type)
        default: break
        }
    }
    return (arrayPoints,arrayTypes)
}
  • I need every single coordinate (CGPoint) which comes under that path. – Deepak Thakur Sep 13 '17 at 10:19
  • There is no image attached. – Tamás Sengel Sep 13 '17 at 10:22
  • https://i.stack.imgur.com/3ZWDe.png Please check this – Deepak Thakur Sep 13 '17 at 10:51
  • 3
    A bezier path is a continuous curve, there are infinitely many points on it. – Martin R Sep 13 '17 at 11:00
  • I want to plot some points which are outside but near to bezier path on the bezier path so for this I need some coordinate through which I can compare them with the nearest point – Deepak Thakur Sep 13 '17 at 11:44
  • `UIBezierPath` does not have function to return random points along the curve. We can show you the bezier algorithm so you can calculate this yourself. Or perhaps you can describe the broader problem you're trying to solve, and perhaps there's a better way to approach it. – Rob Sep 13 '17 at 12:14
  • https://i.stack.imgur.com/jNbmG.png Please check this image. I want to find the point on bezier curve wrt the nearest point. – Deepak Thakur Sep 13 '17 at 12:19
  • @Rob First of all thankyou for your reply I have an array of lat long of user ridden path through which I am creating the bezier path and at some point i want some location on the bezier path though it does not exist on path so for this i need to find out the closest point on bezier curve wrt nearest location as shown in second image. – Deepak Thakur Sep 13 '17 at 12:25
  • This is a pretty complicated problem when your path consists of a series of lines, cubic bezier and quad bezier. You might refer to https://stackoverflow.com/a/2750826/1271826. I would ask whether you really must go through all of that, or whether you simply want to iterate through your original data points to see which is closest. – Rob Sep 13 '17 at 12:47
  • I want to go through all of them. – Deepak Thakur Sep 15 '17 at 10:25
  • 1
    @DeepakThakur my requirement is also same. Can you please help me to find points of UIBezierPath. – Vipulk617 Nov 02 '21 at 08:55

1 Answers1

2

Let's take a step back for a moment. Why do you want all these points? Is it to see if someone is touching the outline of the path? If so use CGPathCreateCopyByStrokingPath to create a new path that is filled where the original was stroked, and then use the new path's containsPoint method. Easy.

If you really want "all" the points you have to accept that mathematically there are an infinite number of points on lines and curves so you can't get them all. In iOS where points are CGFloat pairs there are still too many to practically have "all" the points. You can however get pretty much as many points as you like across any part of the curve, so if say "100 points on the path" or "1000 points on the path" (or pretty much any integer you like) will solve your problem then this is still a solvable problem.

Iterating through each path element is a good start.

For each line you need to generate "all" the points on the line, that is pretty simple geometry: compute a vector from the start point to the end. Iterate from 0.0 to 1.0 in steps as small as you like. Multiply the vector by that fraction, add it to the start point and that is your point.

For each curve you need a more complex equation here is some pseudo code:

function computeCurve(points[], t):
  if(points.length==1):
    recordPoint(points[0])
  else:
    newpoints=array(points.size-1)
    for(i=0; i<newpoints.length; i++):
      newpoints[i] = (1-t) * points[i] + t * points[i+1]
    computeCurve(newpoints, t)

For a seriously good overview of how bezier curves "really work" look at https://pomax.github.io/bezierinfo/ (it has pseudo code - including basically that part I cribbed above, but nothing you can directly execute in Swift).

For code that already does this on iOS look at:

https://github.com/CodingMeSwiftly/UIBezierPath-Superpowers

For macOS I made a fairly minor fork to support the slightly different set of primitives on macOS:

https://github.com/stripes/UIBezierPath-Superpowers

They will give you a new method for UIBezierPath (or NSBezierPath) mx_point(at fraction: CGFloat) that lets you give it a value 0 to 1 and get the point you are interest in. It also has a method to give you the total length of the path so if you don't need "100 points on the path" but "points on the path no more then 3 pixels apart" you can kind-of use that to get some estimates of how fast to step that fraction. It is only a guess because some parts of an arc will "move" faster than others. So you will need to generate each point and if they are too far apart for your usage step back a little.

Good luck!

Stripes
  • 4,161
  • 2
  • 25
  • 29