5

I have a problem in an app I'm working on. Say I have two CGPaths that are fairly complex and I add them both to a CGMutablePath (thus combining them). Well, where the two paths intersect there will be points inside of each other. I want to eliminate those inside points and essentially draw the outside or outline of the path. I am having difficulty figuring out how I would go about this.

Edit: Here's an example of what I am talking about. The blue and red boxes represent points along the CGPaths. The red boxes are the points that are within both paths. I would like to somehow eliminate the red points and redraw just the outline of the path.

enter image description here

daveMac
  • 3,041
  • 3
  • 34
  • 59
  • Do you mean you want to compute the union of the paths? Or do you want the [symmetric difference](http://en.wikipedia.org/wiki/Symmetric_difference) of the paths? – rob mayoff May 31 '12 at 18:16
  • @robmayoff I have edited my question to hopefully clarify what I am trying to do. – daveMac May 31 '12 at 23:09
  • @daveMac : You can refer :- http://stackoverflow.com/questions/23497703/union-uibezierpaths-rather-than-apend-path/41179791#41179791 – Shrawan Dec 16 '16 at 10:09

4 Answers4

3

What you are describing is the union of the paths' interiors.

If your paths contain curves, this is a hard problem.

However, your example shows only straight line segments, so I will assume you only care about paths that solely contain straight line segments.

In that case, you want a polygon union function. This sort of algorithm is pretty basic in the field known as “computational geometry”. I don't know of any Objective-C-specific implementation of polygon union. You might be able to find a pure C library, but it's much easier to find a C++ library. You can use C++ if you change your file extension from .m to .mm. Here are some C++ libraries that can compute the union of polygons:

Note that in all cases, you'll need to use CGPathApply to extract the vertices of your path, if you don't already have them in another format.

rob mayoff
  • 375,296
  • 67
  • 796
  • 848
1

Classic point in polygon problem. Remove all the points in each polygon that return 1 referencing the other polygon:

int pnpoly(int npol, float *xp, float *yp, float x, float y)
{
  int i, j, c = 0;
  for (i = 0, j = npol-1; i < npol; j = i++) {
    if ((((yp[i] <= y) && (y < yp[j])) ||
         ((yp[j] <= y) && (y < yp[i]))) &&
        (x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i]))
      c = !c;
  }
  return c;
}

Combine the two paths with the removed points.

Pseudo code for the whole procedure:

define starPoly with 10 points
define simplePoly with 7 points

for each point in starPoly
    if ( pnpoly( 7, simplePoly.Xs[], simplePoly.Ys[], point.x, point.y ) == 0 )
        clipedStarPoly += point;

for each point in simplePoly
    if ( pnpoly( 10, starPoly.Xs[], starPoly.Ys[], point.x, point.y ) == 0 )
        clipedSimplePoly += point;

for each point in clipedStarPoly
    solutionPoly += point;

for each point in clipedSimplePoly
    solutionPoly += point;

solutionPoly += solutionPoly.point[0]

If you don't think you will have to play with the endpoints of the clipped polys you can simply build the solution poly directly out of the point tests.

You may want to use ray tracing for the point in poly test, try looking at this page

gjpc
  • 1,428
  • 14
  • 21
  • 1
    How about a little explanation as to how exactly to use this, where to use this, and what it is doing. – daveMac Jun 05 '12 at 13:55
  • Hey Dave, is that enough explanation? – gjpc Jun 06 '12 at 16:02
  • I think I understand pretty well. I know that is just pseudo code but I think that it would really help to see a working example using CGPaths. – daveMac Jun 06 '12 at 17:27
  • 2
    gjpc this is not a complete solution to my question. I never confirmed that it was either, I just simply said that I think I understand what it is that you are suggesting. You are simply removing points but as I have experimented on a solution for this issue for quite some time now, it is far more complex than this. You must not only remove unwanted points but you must add new points at new intersections. Furthermore, your solution is very vague in that it does not use the particulars of a CGPath and therefore is a bit confusing as to how exactly it should be written. – daveMac Jun 07 '12 at 16:04
  • 2
    I have been programming for two years now and take pride in trying to always figure out the solutions myself if I am able, however I have no idea what you are writing when you write something like: "( pnpoly( 7, simplePoly.Xs[], simplePoly.Ys[], point.x, point.y ) == 0 )" What exactly am I passing in when I write "simplePoly.Xs[]"? and where am I getting "point.x" and "point.y" from? Forgive my ignorance, but this does not appear to be a thorough or complete answer to my question and in its present state does not warrant the bounty (whether I've already lost it or not is beside the point). – daveMac Jun 07 '12 at 16:08
  • My last two comments don't seem to have any context now, but gjpc said he wouldn't write my code for me and that I should award the bounty to him. His comment has since been removed but fyi, that's the context of my last two comments. – daveMac Jun 08 '12 at 15:08
  • There's a crucial stage missing from this solution. Note that the combined polygon will contain two points that are not included in either path - those where the two polygons cross each other. – Ash Dec 08 '13 at 09:13
  • I'll never go for a bounty again – gjpc Dec 09 '13 at 16:05
0

Use CGPathAddPath. Super easy to use.

0

It's not enough to simply union two sets of points. In order to determine the combined polygons, you would need to do the following. Sorry I only have pseudocode, I only just started looking at this problem.

We will consider the two polygons to be A and B. It does not matter which is which.

  • Move around polygon A looking for any point that is NOT inside polygon B.
  • Add this point to the polygon.
  • Continue around the polygon, testing and adding each point in turn.
  • When you discover a point that IS inside polygon B, look at the line between it and the previous point.
  • Find out which line on polygon B intersects with this line.
  • Determine the point of intersection between these two lines and add it to the polygon.
  • Determine which of the two points that define the intersecting line belonging to polygon B is NOT inside polygon A and add that to the new polygon.
  • Determine which direction around polygon B you need to go in order that the next point will NOT be the one on the other end of the line of intersection and add it.
  • Repeat from 3, except using polygon B instead of polygon A
  • Continue until you reach the point you started from, swapping between polygons as necessary.

Note that this solution is only acceptable for straight-sided polygons. Where a bezier path is concerned, it becomes a lot more difficult to calculate the points of intersection, not to mention the complexities of combining smooth corners with sharp corners, or curves with straight line segments.

Ash
  • 9,064
  • 3
  • 48
  • 59