Where do I release CGMutablePathRef? - ios

I have to release CGMutablePathRef before returning it else the application is crashes. Where should I be releasing it?
I have tried before returning but its still crashing...
+(UIBezierPath*) smoothedBezierOutlinePathWithCGPath:(CGPathRef)path tension:(CGFloat) tension
{
CGMutablePathRef smoothedCGPath = CreateSmoothedBezierPathFromPath(path, tension);
UIBezierPath* smoothedBezierPath = [UIBezierPath bezierPathWithCGPath:smoothedCGPath];
CGPathRelease(smoothedCGPath);
return smoothedBezierPath;
}
CGMutablePathRef CreateSmoothedBezierPathFromPath( CGPathRef path, CGFloat tention)
{
//convert path to 2 arrays of CGFloats
struct dataPointer my_dataPointer; //this struct will hold the 2 indexes of the CGpath
my_dataPointer.numberOfPoints = 0;
my_dataPointer.isClosed = NO;
CGPathApply(path, &my_dataPointer, savePathToArraysApplierFunc);
//the arrays where the control points will be stored
CGFloat controlPoints_x[2*_max_points];
CGFloat controlPoints_y[2*_max_points];
calculateBezierControlPoints( controlPoints_x, controlPoints_y, my_dataPointer.indexx , my_dataPointer.indexy, my_dataPointer.isClosed, my_dataPointer.numberOfPoints, tention);
//the final CGpath constisting of original points and computed control points
CGMutablePathRef bezierPath = CGPathCreateMutable();
for (int i = 0; i<my_dataPointer.numberOfPoints + (int) my_dataPointer.isClosed; i++)
{
if(i==0)
CGPathMoveToPoint(bezierPath, nil, my_dataPointer.indexx[0], my_dataPointer.indexy[0]);
else if (i==my_dataPointer.numberOfPoints) //this happens when the path is closed
CGPathAddCurveToPoint(bezierPath, nil, controlPoints_x[i*2-2], controlPoints_y[i*2-2], controlPoints_x[i*2-1], controlPoints_y[i*2-1],my_dataPointer.indexx[0], my_dataPointer.indexy[0]);
else
CGPathAddCurveToPoint(bezierPath, nil, controlPoints_x[i*2-2], controlPoints_y[i*2-2], controlPoints_x[i*2-1], controlPoints_y[i*2-1],my_dataPointer.indexx[i], my_dataPointer.indexy[i]);
}
if(my_dataPointer.isClosed)
CGPathCloseSubpath(bezierPath);
//app crashes here before returning.
return bezierPath;
}
Where am I suppose to release it? I have tried releasing it declaring it globally too but no use. Please can anyone help me?

Related

How to check if anyone is enter/left in/from particular boundary area even if application is in background mode or kill mode?

I want to check if anyone enter in allocated boundary then i have to alert that user like "You are entered" and when user leaves then "You left". I am using .KML file for draw boundary in which there are more than latitude and longitude. Here i attached screenshot for the same.So, my concern is that how can i detect that anyone is entered within this boundary and left from that boundary. Thank you in advance
Boundary looks like this.Red color line is boundary.
Use map rects. Here's an example using the map's current visible rect. With regards to your question, you could use convertRegion:toRectToView: to first convert your region to a MKMapRect beforehand.
MKMapPoint userPoint = MKMapPointForCoordinate(mapView.userLocation.location.coordinate);
MKMapRect mapRect = mapView.visibleMapRect; // find visible map rect
//MKMapRect mapRect = [self getMapRectUsingAnnotations:arrCordinate];//find custom map rect
BOOL inside = MKMapRectContainsPoint(mapRect, userPoint);
MKMapRect mapRect = mapView.visibleMapRect;
Create your custom mapRect using your boundary region from multiple latitude and longitude
- (MKMapRect) getMapRectUsingAnnotations:(NSArray*)arrCordinate {
MKMapPoint points[[arrCordinate count]];
for (int i = 0; i < [arrCordinate count]; i++) {
points[i] = MKMapPointForCoordinate([arrCordinate[i] MKCoordinateValue]);
}
MKPolygon *poly = [MKPolygon polygonWithPoints:points count:[arrCordinate count]];
return [poly boundingMapRect];
}
Geofencing will not work on complex polygon shaped regions. May be you can solve the problem with some other approach. For instance divide the region into smaller CLCircularRegion and then develop aggregate logic for the case where you have to show notification for all those locationManager:didEnterRegion: and locationManager:didExitRegion: callbacks. But keep in mind that only a max of 20 simultaneous monitored regions per app are allowed.
Refer https://forums.developer.apple.com/thread/21323 phillippk1 suggestion for other possible approach.
Try this code. This is based on Winding Number Algorithm. This works for complex shapes such as your red line.
typedef struct {
double lon;
double lat;
} LATLON;
// returns true if w/in region
bool chkInRegion(LATLON poi, int npoi, LATLON *latlon)
{
int wn = 0;
for (int i = 0 ; i < npoi-1 ; i++) {
if (latlon[i].lat <= poi.lat && latlon[i+1].lat > poi.lat) {
double vt = (poi.lat - latlon[i].lat)/(latlon[i+1].lat - latlon[i].lat);
if (poi.lon < (latlon[i].lon + (vt * (latlon[i+1].lon - latlon[i].lon)))) {
wn++;
}
} else if (latlon[i].lat > poi.lat && latlon[i+1].lat <= poi.lat) {
double vt = (poi.lat - latlon[i].lat)/(latlon[i+1].lat - latlon[i].lat);
if (poi.lon < (latlon[i].lon + (vt * (latlon[i+1].lon - latlon[i].lon)))) {
wn--;
}
}
}
return wn < 0;
}
// test data
LATLON llval[] = {
{100,100},
{200,500},
{600,500},
{700,100},
{400,300},
{100,100}
};
#define NLATLON (sizeof(llval)/sizeof(LATLON))
int main(int argc, char **argv) {
while (1) {
char buf[1024];
fprintf(stderr, "lon = ");
fgets(buf, sizeof(buf), stdin);
double lon = atof(buf);
fprintf(stderr, "lat = ");
fgets(buf, sizeof(buf), stdin);
double lat = atof(buf);
LATLON ltest;
ltest.lat = lat;
ltest.lon = lon;
if (chkInRegion(ltest, NLATLON, llval)) {
fprintf(stderr, "\n*** in region ***\n\n");
} else {
fprintf(stderr, "\n=== outside ===\n\n");
}
}
return 0;
}

convert NSMutableArray to CGPoint Array

the typical answer will be "you can convert it to nsvalue and then use [element CGPointValue];
but in my case i need to generate array of type CGPoint , as i need it in a built in function below :
static CGPathRef createClosedPathWithPoints(const CGPoint *points, size_t count) {
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddLines(path, NULL, points, count);
CGPathCloseSubpath(path);
return path;
}
so , i need to pass the exact datatype , as i can't parse it element by element , or i need a way to everytime the user make a specific action , i add it's CGPoint to array of CGPoints :((
thanks in advance
edit :
i have tried malloc and making c array but the result of the function was not desirable , i tested and made infinity for loop to that malloc array , and it's too large not just like the size i sat , and contain garbage so the result went wrong
this is the mutable array
pointToPoints = [NSMutableArray new];
[pointToPoints addObject:[NSValue valueWithCGPoint:tempPoint] ];
Here is something that will create a closed path from an NSArray of NSValue created with CGPoint using the code your provided:
BOOL isCGPoint(NSValue *value){
return value && strcmp([value objCType], #encode(CGPoint)) == 0;
}
- (CGPathRef) closedPathFromPointArray:(NSArray *)points{
CGMutablePathRef path = CGPathCreateMutable();
if(points.count){
CGPoint origin = ((NSValue *)points[0]).CGPointValue;
CGPathMoveToPoint (path, NULL, origin.x, origin.y);
// see https://developer.apple.com/library/mac/documentation/GraphicsImaging/Reference/CGPath/#//apple_ref/c/func/CGPathAddLines
for(NSValue *value in points){
CGPathAddLineToPoint (path, NULL, value.CGPointValue.x, value.CGPointValue.y);
}
}
CGPathCloseSubpath(path);
return path;
}
As you see, you don't really need malloc, or even creating a C array of CGPoint. This assumes you only need this array for creating the closed path.
Two extra things of note:
See the commented link for CGPathAddLines, as it describes how CGPathAddLines works internally. This gives you the hint about how to go about this.
The isCGPoint function is included so you can test if a given NSValue instance was actually created using [NSValue valueWithCGPoint:]. My previous answer checked this, but I thought it was ooverkill to check everywhere. In any case, it's included here for didactic purposes.
CGPoint *points = malloc(sizeof(CGPoint) * mutableArrayOfPoints.count);
for (int i = 0; i < mutableArrayOfPoints.count; i++) {
points[i] = [mutableArrayOfPoints[i] pointValue];
}
The above is from memory. I haven't used malloc() in ages, so you may need to adjust syntax.

CGRectFromString() for general structs

#"{0, 1.0, 0, 1.0}"
I wish to convert the above string to a struct like this:
struct MyVector4 {
CGFloat one;
CGFloat two;
CGFloat three;
CGFloat four;
};
typedef struct MyVector4 MyVector4;
CGRectFromString() does the same thing, only for CGRect. How can I do it for my own structs?
If there is a function for rect it means that it is not working by default.
You have to create your own function something like MyVector4FromString.
You may like to to know that you can init struct object like this also.
MyVector4 v1 = {1.1, 2.2, 3.3, 4.4};
This is a very easy C syntax. so I don't think you require to init from string.
See here : 4.7 — Structs
But if you are getting string from server or from other function than yes you have to create your function to do this. You can parse string and init 4 float value.
This link will help you to divide string in multiple part : Split a String into an Array
All the best.
It can be done in the following way:
-(MyVector4)myVector4FromString:(NSString*)string
{
NSString *str = nil;
str = [string substringWithRange:NSMakeRange(1, string.length - 1)];
NSArray *strs = [str componentsSeparatedByString:#","];
MyVector4 myVec4 = {0,0,0,0};
for (int i=0; i<4; i++)
{
CGFloat value = ((NSString*)[strs objectAtIndex:i]).floatValue;
if (i==0) { myVec4.one = value; } else
if (i==1) { myVec4.two = value; } else
if (i==2) { myVec4.three = value; } else
if (i==3) { myVec4.four = value; }
}
return myVec4;
}
This function can parse strings in format shown in your question like #"{12.0,24.034,0.98,100}"

How to Create a Dynamic CGPoint** array

I have a few maps (tilemaps made with Tiled QT) and I would like to create a CGpoint **array based on the objects groups of those maps (I call them Waypoints).
Each maps can have a few set of waypoints that I call path.
//Create the first dimension
int nbrOfPaths = [[self.tileMap objectGroups] count];
CGPoint **pathArray = malloc(nbrOfPaths * sizeof(CGPoint *));
Then for the second dimension
//Create the second dimension
int pathCounter = 0;
while ((path = [self.tileMap objectGroupNamed:[NSString stringWithFormat:#"Path%d", pathCounter]])) {
int nbrOfWpts = 0;
while ((waypoint = [path objectNamed:[NSString stringWithFormat:#"Wpt%d", nbrOfWpts]])) {
nbrOfWpts++;
}
pathArray[pathCounter] = malloc(nbrOfWpts * sizeof(CGPoint));
pathCounter++;
}
Now I want to fill up the pathArray
//Fill the array
pathCounter = 0;
while ((path = [self.tileMap objectGroupNamed:[NSString stringWithFormat:#"Path%d", pathCounter]]))
{
int waypointCounter = 0;
//Get all the waypoints from the path
while ((waypoint = [path objectNamed:[NSString stringWithFormat:#"Wpt%d", waypointCounter]]))
{
pathArray[pathCounter][waypointCounter].x = [[waypoint valueForKey:#"x"] intValue];
pathArray[pathCounter][waypointCounter].y = [[waypoint valueForKey:#"y"] intValue];
NSLog(#"x : %f & y : %f",pathArray[pathCounter][waypointCounter].x,pathArray[pathCounter][waypointCounter].y);
waypointCounter++;
}
pathCounter++;
}
When I NSLog(#"%#",pathArray), it shows me the entire pathArray will the x and y.
HOWEVER 2 problems :
The y value is never correct (the x value is correct and my tilemap.tmx is correct too)
<object name="Wpt0" x="-18" y="304"/> <-- I get x : -18 and y :336 with NSLog
<object name="Wpt1" x="111" y="304"/> <-- I get x : 111 and y :336
<object name="Wpt2" x="112" y="207"/> <-- I get x : 112 and y :433
I get a EX_BAD_ACCESS at the end of the NSLog
EDIT
Thank you about the NSLog(%#) concerning CGPoint.
However, I get the y value with this line (in the ugly loop):
NSLog(#"x : %f & y : %f",pathArray[pathCounter][waypointCounter].x,pathArray[pathCounter][waypointCounter].y);
First of all, you can't NSLog CGPoint like that because it is not an object. %# expects an objective c object to send a description message to.
Secondly, you can use an NSValue wrapper and then use NSMutableArray as you would with any other object. Is there a reason you don't want to do that? You can add arrays inside other arrays as you are doing.
Regarding the first problem:
The y value is never correct (the x value is correct and my tilemap.tmx is correct too)
Have you noticed that if you add the y values from tile map and from NSLog they always add up to 640? Then you better check if tilemap y-coordinate is top-to-bottom as oppose to CGPoint's bottom-to-top. Then you can always do 640 - y to convert the y-coordinate between the two coordinate systems.

Getting a b2Fixture of a b2body Box2d?

I have around 10 bodies in my Box2D sample app which i have created with the help of following method. But in my Update method i want get the b2FixtureDef of the bodies because i need there filter.groupIndex which is different for every body. I have the Update method as follows which loops thru all the b2Body but cant really find how to get the b2FixtureDef from b2Body??
-(void) addNewSprite:(NSString *)spriteName AtPosition:(CGPoint)p isDynamic:(BOOL)dynamic
{
//CCNode *parent = [self getChildByTag:kTagParentNode];
PhysicsSprite *sprite = [PhysicsSprite spriteWithFile:spriteName];
[self addChild:sprite];
sprite.position = ccp( p.x, p.y);
sprite.tag = check;
// Define the dynamic body.
//Set up a 1m squared box in the physics world
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(sprite.position.x/PTM_RATIO, sprite.position.y/PTM_RATIO);
bodyDef.userData = sprite;
b2Body *body = world->CreateBody(&bodyDef);
// Define another box shape for our dynamic body.
b2PolygonShape dynamicBox;
dynamicBox.SetAsBox((sprite.contentSize.width/PTM_RATIO/2)*(sprite.scaleX),
(sprite.contentSize.height/PTM_RATIO/2)*(sprite.scaleY));//These are mid points for our 1m box
// Define the dynamic body fixture.
b2FixtureDef fixtureDef;
fixtureDef.shape = &dynamicBox;
fixtureDef.density = 1.0f;
fixtureDef.friction = 1.0f;
fixtureDef.userData = sprite;
switch (check)
{
case 1:
fixtureDef.filter.categoryBits = 0x0002;
fixtureDef.filter.maskBits = 0x0004;
break;
case 2:
fixtureDef.filter.categoryBits = 0x0004;
fixtureDef.filter.maskBits = 0x0002;
break;
}
body->CreateFixture(&fixtureDef);
[sprite setPhysicsBody:body];
check++;
}
-(void) update: (ccTime) dt
{
//It is recommended that a fixed time step is used with Box2D for stability
//of the simulation, however, we are using a variable time step here.
//You need to make an informed choice, the following URL is useful
//http://gafferongames.com/game-physics/fix-your-timestep/
int32 velocityIterations = 8;
int32 positionIterations = 1;
// Instruct the world to perform a single step of simulation. It is
// generally best to keep the time step and iterations fixed.
world->Step(dt, velocityIterations, positionIterations);
for(b2Body *b = world->GetBodyList(); b; b=b->GetNext()) {
if (b->GetUserData() != NULL)
{
//b2Fixture fixtureDef = *b->GetFixtureList();
//b2Filter filter = fixtureDef.GetFilterData();
// how to get b2FixtureDef from b
}
}
Actually, i cannot imagine why do you need to get this info in your update method. You cannot get fixtureDef, as it is used for fixture creation only. But you can get filter data for each body fixture using GetFilterData() method. It will contain category bits, mask bits and group index.

Resources