18

I have made a quad curve path using the method CGPathAddQuadCurveToPoint. I got the path perfectly. But, I want to know all the coordinate points which are participated in the path.

Is there a way to retrieve all the coordinate points in a path?

If not do u have any other solution for retrieving all the points in a curve mathematically.

Thanks in advance, Vamshi

Leo
  • 24,596
  • 11
  • 71
  • 92
  • Here ... http://stackoverflow.com/questions/4854035/how-do-i-detect-a-touch-on-a-uibezierpath-and-move-a-ball-along-that/4855932#4855932 – Fattie Jul 06 '11 at 06:50

6 Answers6

14

You can do this using the wykobi C++ library routine for cubic bezier curves. Wykobi's library supports quadratic Bezier curves also.

Of course as someone pointed out you don't want all the points (although not impossible, it would just take infinite time :). Wykobi makes it easy to get a certain number of points -- if your start, c1, c2, and end points (where c1, c2 are the control points) are exactly the same as the ones given to CGContextAddCurveToPoint then the points will lie perfectly on the line drawn by core graphics -- so you can do things like draw a pattern at several points on the path.

See: http://www.codeproject.com/Articles/22568/Computational-Geometry-C-and-Wykobi

Also, after I started using wykobi I heard that there is a similar, maybe even better library that is part of Boost, but have not checked it out yet.

I created a C++ Class WPoint as a bridge between wykobi points and CGPoints (C++ fun!). Here's some code (without WPoint, but you can imagine that it is exactly the same layout as a CGPoint so if you do the right cast you can convert easily.

        NSMutableArray* result = [[NSMutableArray alloc] init];
        wykobi::cubic_bezier<CGFloat,2> bezier;
        bezier[0] = (WPoint)p1;  // start point, in CG we did a CGMoveToPoint
        bezier[1] = (WPoint)b1i; // control 1
        bezier[2] = (WPoint)b2i; // control 2
        bezier[3] = (WPoint)p2;  // end point

        std::vector<WPoint> point_list;
        int numPoints = p2.dist(p3) * pointDensity;
        // *** here's the magic ***
        wykobi::generate_bezier(bezier,std::back_inserter(point_list), numPoints);

        for (int i=0; i<numPoints; i++) {
            CGPoint p = (CGPoint)(point_list[i]);
            [result addObject:[NSValue valueWithCGPoint:p]];
        }

// result has your points!

Here's a link to the Boost geometry library: http://www.boost.org/doc/libs/1_47_0/libs/geometry/doc/html/geometry/introduction.html

George C.
  • 681
  • 1
  • 6
  • 11
2

Use CGContextSetLineDash

The purpose of this function is to create a dashed line, but You can use it to get smaller segments. starting point of each segment can be treated as points.

CGSize bbSize = CGPathGetBoundingBox(path).size;
UIGraphicsBeginImageContext(bbSize);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(ctx, 1.0);
CGContextAddPath(ctx, path);
CGContextSetLineDash(ctx, phase, lengths, count);
CGContextReplacePathWithStrokedPath(ctx);
result = CGContextCopyPath(ctx);
UIGraphicsEndImageContext();
enRaiser
  • 2,606
  • 2
  • 21
  • 39
  • This helped me. I also needed to use CGApplyPath to get the points from the elements out... I still have some tuning to do, but this works pretty good. By tuning I mean to try different settings of the `lengths` parameter. – Jonny Mar 31 '15 at 11:24
  • 1
    Why not use `CGPathCreateCopyByDashingPath`? – Ilya Jul 26 '15 at 23:35
1

If you want to work on the moveto, lineto, and curveto elements of the path, use CGPathApply. You pass this a pointer to a function in your program, and it calls that function once per element of the path.

Unfortunately, there's no way to just ask for each element like there is with AppKit's NSBezierPath. The function is the only way.

If you want to determine every pixel intersected by the path, too bad—that's not practical, and I can't even think of why you'd want that information. Some contexts, such as PDF contexts, don't even have pixels; in those cases, any question involving pixels is a non sequitur.

Peter Hosey
  • 95,783
  • 15
  • 211
  • 370
0

A quadratic curve is just that -- a curve. It's impossible to get a list of all of the points on it because there are infinitely many points, and it's not a simple line segment.

See Getting Information about Quartz Paths for a list of the functions you can use to query a CGPath object. Unfortunately, it seems like the most useful information you're going to get is with CGPathContainsPoint(), which only tells you if a given point is contained within the area of the path.

Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
  • Thanks for the reply.. I have used the CGPathContainsPoint(). For using this method, we definitely need our path to be closed. But, in my case if I close the path then I will not get the expected path. If it we want to find all the points in between two points (it becomes a straight line) then there is a solution using Maths equations. Is there any solution for curves using Maths equations or any algorithm –  May 08 '09 at 18:38
0

If not do u have any other solution for retrieving all the points in a curve mathematically.

What do you need them for, i.e. what problem are you trying to solve? If it is to intersect two curves, you can do this mathematically. Just set the two curve equations equal to each other and solve for the unknown.

Alex Reynolds
  • 95,983
  • 54
  • 240
  • 345
  • Thanks for the reply.. I am having a prob where I want to move an object(eg. Person) on the path. I can use CAKeyFrameAnimation to solve my problem wherer it needs the duration. But, I dont have duration in my case. While the object is moving I have to do some other operations on object like jumping or moving back etc. So, if I knw all the points on the path then I can make him to move on the points which will satisfy my requirement. –  May 09 '09 at 03:40
  • I don't understand the problem fully, but perhaps making your path time-based will help you solve this. That is, at t=0, the path equation puts the object at (x0, y0). At t=1, the path puts the object at (x1, y1). And so forth. Then, you do not need to remember all points, but simply calculate the (xi, yi) for time point t=i. – Alex Reynolds May 09 '09 at 05:16
0

I guess you're after something equivalent to the Java2D FlatteningPathIterator class. For example Java2D's path.getPathIterator(null, 1.0) returns an iterator of only 'lineTo' segments even if the original path had curveTo and quadTo, the double argument controls the 'flatness', giving you an easy way to calculate any point on the curve. I'm searching for the same thing in Cocoa, but have found nothing. If you find a solution please let me know. There are curve implmentations around (e.g. http://sourceforge.net/projects/curves/) that could be ported, but there's always a risk that if you don't use the same algorithm as Cocoa then there could be errors between your interpolation and the stroked NSBezierPath/CGPath.