Spritekit - Objective C - Add SKShapenodes to an array and then remove nodes one by one via button - ios

Essentially I draw multiple lines on the screen by using a SKShapenode and adding it to a dictionary.
I want to now store the SKShapenodes in a array and remove the last item in the array via a button. Any idea anyone?
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch* touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
SKLabelNode *touchedNode = (SKLabelNode *)[self nodeAtPoint:positionInScene];
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
// Create a mutable path
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:location];
// Create a shape node using the path
lineNode = [SKShapeNode shapeNodeWithPath:path.CGPath];
lineNode.strokeColor = [SKColor blackColor];
lineNode.glowWidth = 3.0;
[_gameLineNode addChild:lineNode];
// Use touch pointer as the dictionary key. Since the dictionary key must conform to
// NSCopying, box the touch pointer in an NSValue
NSValue *key = [NSValue valueWithPointer:(void *)touch];
[lines setObject:lineNode forKey:key];
_lineNodeArray = [NSMutableArray array];
for (int i = 0; i < 10; i++) {
[_lineNodeArray addObject:lineNode];
}
}
}
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
// Retrieve the shape node that corresponds to touch
NSValue *key = [NSValue valueWithPointer:(void *)touch];
lineNode = [lines objectForKey:key];
if (lineNode != NULL) {
// Create and initial a mutable path with the lineNode's path
UIBezierPath *path = [UIBezierPath bezierPathWithCGPath:lineNode.path];
// Add a line to the current touch point
[path addLineToPoint:location];
// Update lineNode
lineNode.path = path.CGPath;
lineNode.physicsBody = [SKPhysicsBody bodyWithEdgeChainFromPath:path.CGPath];
lineNode.physicsBody.categoryBitMask = lineNodeCategory;
lineNode.physicsBody.contactTestBitMask = bubble1Category | bubble2Category| bubble3Category | bubble4Category | bubble5Category | bubble6Category;
lineNode.physicsBody.collisionBitMask = ballCategory | ballHalf1Category | ballHalf2Category;
lineNode.physicsBody.dynamic = YES;
lineNode.name = lineNodeCategoryName;
CGPoint _currentPoint = [[touches anyObject] locationInNode:self];
CGPoint _previousPoint = [[touches anyObject] previousLocationInNode:self];
_delta = CGPointMake(_currentPoint.x - _previousPoint.x, _currentPoint.y - _previousPoint.y);
}
}
}
Delete action - This will remove the line from the array but how do i remove the last line from the game view?
-(void)deleteLine{
_lineNodeArray = [NSMutableArray array];
[_lineNodeArray lastObject ];
[_lineNodeArray removeLastObject];
}

Related

Spritekit - calculate distance the finger has travelled between two events to increment your a NSUInteger

I use the following code to draw a line from point Touch point A to Touch point B.
The code also allows me to draw multiple lines simultaneously.
My first attempt was to create a NSUInteger and increase it by 1 per pixel moved in touchesMoved. However the increment is not consistent. It appears that moving your finger fast will increase the number slowly whereas moving your finger slowly will increase the number fast.
I think I need to calculate the distance moved between two events and then increment the number. I don't know how to do this, can anyone help?
//Create a line at first point of touch
(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch* touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
SKLabelNode *touchedNode = (SKLabelNode *)[self nodeAtPoint:positionInScene];
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
// Create a mutable path
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:location];
// Create a shape node using the path
lineNode = [SKShapeNode shapeNodeWithPath:path.CGPath];
lineNode.strokeColor = [SKColor blackColor];
lineNode.glowWidth = 3.0;
[_gameLineNode addChild:lineNode];
// Use touch pointer as the dictionary key. Since the dictionary key must conform to
// NSCopying, box the touch pointer in an NSValue
NSValue *key = [NSValue valueWithPointer:(void *)touch];
[lines setObject:lineNode forKey:key];
}
}
// Draw the line to last touch point dynamically
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
// Retrieve the shape node that corresponds to touch
NSValue *key = [NSValue valueWithPointer:(void *)touch];
lineNode = [lines objectForKey:key];
if (lineNode != NULL) {
// Create and initial a mutable path with the lineNode's path
UIBezierPath *path = [UIBezierPath bezierPathWithCGPath:lineNode.path];
// Add a line to the current touch point
[path addLineToPoint:location];
// Update lineNode
lineNode.path = path.CGPath;
lineNode.physicsBody = [SKPhysicsBody bodyWithEdgeChainFromPath:path.CGPath];
lineNode.physicsBody.categoryBitMask = lineNodeCategory;
lineNode.physicsBody.contactTestBitMask = bubble1Category | bubble2Category| bubble3Category | bubble4Category | bubble5Category | bubble6Category;
lineNode.physicsBody.collisionBitMask = ballCategory | ballHalf1Category | ballHalf2Category;
lineNode.physicsBody.dynamic = YES;
lineNode.name = lineNodeCategoryName;
//ATTEMPT 1 - NSUINTEGER that increases per pixal moved
testNumber ++;
testLabel.text = [NSString stringWithFormat:#"%lu",(unsigned long)testNumber];
}
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
inkLockOrUnlock = [[NSUserDefaults standardUserDefaults] boolForKey:#"inkLockOrUnlock"];
if (inkLockOrUnlock == NO) {
SKAction *block0 = [SKAction runBlock:^{
for (UITouch *touch in touches) {
NSValue *key = [NSValue valueWithPointer:(void *)touch];
[lines removeObjectForKey:key];
}
[_gameLineNode removeAllChildren];
}];
SKAction *inkAnimation = [SKAction sequence:#[block0,]];
[self runAction:[SKAction repeatAction:inkAnimation count:1]];
} else {}
}
If I understand you, I think you might be misunderstanding a lot here. Every time touchMoved gets called, it gives you an xy coord for current position of that touch. That function can only be called max once per frame.
It sounds like you are thinking the function is called for every pixel the touch gets moved, which is not the case.
So store the initial point from touchBegan, then use math to determine distance between initial point and the current point inside touchMoved.
But also keep in mind that points don't necessarily equal pixels.

Spritekit - Using gestures to draw multiple lines with multiple fingers simultaneously

Using the below code, I can draw a line using the pan gesture using 1 finger. However what I am attempting to do is for 1 finger to draw 1 line and another finger to draw the second simultaneously. I've read somewhere about using a dictionary to store the touches but don't know how to write it in code. Can any one help?
-(void)didMoveToView:(SKView *)view {
UIPanGestureRecognizer *gestureRecognizerPan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePanFrom:)];
[[self view] addGestureRecognizer:gestureRecognizerPan];
}
- (void)handlePanFrom:(UIPanGestureRecognizer *)recognizer
{
if (recognizer.state == UIGestureRecognizerStateBegan) {
CGPoint touchLocation = [recognizer locationInView:recognizer.view];
touchLocation = [self convertPointFromView:touchLocation];
pathToDraw = CGPathCreateMutable();
CGPathMoveToPoint(pathToDraw, NULL, touchLocation.x, touchLocation.y);
lineNode = [[SKShapeNode alloc] init];
lineNode.path = pathToDraw;
lineNode.name = lineNodeCategoryName;
[_gameLineNode addChild:lineNode];
} else if (recognizer.state == UIGestureRecognizerStateChanged) {
CGPoint touchLocation = [recognizer locationInView:recognizer.view];
touchLocation = [self convertPointFromView:touchLocation];
CGPathAddLineToPoint(pathToDraw, NULL, touchLocation.x, touchLocation.y);
lineNode.path = pathToDraw;
lineNode.name = lineNodeCategoryName;
lineNode.physicsBody = [SKPhysicsBody bodyWithEdgeChainFromPath:pathToDraw];
lineNode.physicsBody.dynamic = YES;
lineNode.strokeColor = [SKColor blackColor];
lineNode.glowWidth = 3.0;
} else if (recognizer.state == UIGestureRecognizerStateEnded) {
CGPathRelease(pathToDraw);
}
}
Drawing multiple lines simultaneously is fairly straightforward. The key is to track each touch event independently. One way to do that is to maintain a dictionary that uses the touch event as the key and the shape node (used to draw the line) as the value.
#implementation GameScene {
NSMutableDictionary *lines;
}
-(void)didMoveToView:(SKView *)view {
self.scaleMode = SKSceneScaleModeResizeFill;
// Create a mutable dictionary
lines = [NSMutableDictionary dictionaryWithCapacity:10];
}
// Add each line node to the dictionary with the touch event as the key
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
// Create a mutable path
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:location];
// Create a shape node using the path
SKShapeNode *lineNode = [SKShapeNode shapeNodeWithPath:path.CGPath];
lineNode.strokeColor = [SKColor blackColor];
[self addChild:lineNode];
// Use touch pointer as the dictionary key. Since the dictionary key must conform to
// NSCopying, box the touch pointer in an NSValue
NSValue *key = [NSValue valueWithPointer:(void *)touch];
[lines setObject:lineNode forKey:key];
}
}
// Update the lines as needed
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
// Retrieve the shape node that corresponds to touch
NSValue *key = [NSValue valueWithPointer:(void *)touch];
SKShapeNode *lineNode = [lines objectForKey:key];
if (lineNode != NULL) {
// Create and initialize a mutable path with the lineNode's current path
UIBezierPath *path = [UIBezierPath bezierPathWithCGPath:lineNode.path];
// Add a line to the current touch point
[path addLineToPoint:location];
// Update lineNode
lineNode.path = path.CGPath;
}
}
}
// Remove the line nodes from the dictionary when the touch ends
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
NSValue *key = [NSValue valueWithPointer:(void *)touch];
[lines removeObjectForKey:key];
}
}
#end

didBeginContact method not working as intended

I have two nodes and a boolean. Simple enough. When node A contacts Node B and the boolean is 0, nothing happens. However if the boolean is 1, Node A is removed through the didBeganContact method.
Extremely simple, however I have an annoying problem on when I want Node A removed.
Node B is a rectangle and node A is a square going in the middle of the rectangle, the boolean is called and turned into 1 when I tap and hold the Node B using the touchesBegan method. Now before Node A contacts Node B, I tap and hold Node B and when Node A contacts, its removed, but when Node A is already in the middle, and I tap Node B, nothing happens and I don't know why.
Rectangle Method
-(void)rectangle
{
SKSpriteNode *rectangle = [[SKSpriteNode alloc] init];
rectangle = [SKSpriteNode spriteNodeWithColor:[UIColor blueColor] size:CGSizeMake(75, 150)];
rectangle.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
rectangle.name = #"rect";
rectangle.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:rectangle.size];
rectangle.physicsBody.categoryBitMask = rectangleCategory;
rectangle.physicsBody.contactTestBitMask = fallingSquareCategory;
rectangle.physicsBody.collisionBitMask = 0;
[self addChild:rectangle];
}
touchesBeganMethod
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if ([node.name isEqualToString:#"rect"])
{
radBool = 1;
}
}
touchesEnded
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if ([node.name isEqualToString:#"rect"])
{
radBool = 0;
}
}
square Method
-(void)square
{
SKAction *move = [SKAction moveToY:CGRectGetMidY(self.frame) duration:1.75];
SKSpriteNode *fallingSquare = [[SKSpriteNode alloc] init];
fallingSquare = [SKSpriteNode spriteNodeWithColor:[UIColor yellowColor] size:CGSizeMake(75, 75)];
fallingSquare.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMaxY(self.frame));
fallingSquare.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:fallingSquare.size];
fallingSquare.physicsBody.categoryBitMask = fallingSquareCategory;
fallingSquare.physicsBody.contactTestBitMask = rectangleCategory
fallingSquare.physicsBody.collisionBitMask = 0;
[self addChild:fallingSquare];
[fallingSquare runAction:move];
}
didBeginContact
static inline SKSpriteNode *nodeFromBody(SKPhysicsBody *body1, SKPhysicsBody *body2, uint32_t category) {
SKSpriteNode *node = nil;
if (body1.categoryBitMask & category) {
node = (SKSpriteNode *)body1.node;
}
else if (body2.categoryBitMask & category) {
node = (SKSpriteNode *)body2.node;
}
return node;
}
-(void)didBeginContact:(SKPhysicsContact *)contact
{
SKPhysicsBody *firstBody, *secondBody;
SKSpriteNode *R1 = nil;
SKSpriteNode *fallingS = nil;
firstBody = contact.bodyA;
secondBody = contact.bodyB;
R1 = nodeFromBody(firstBody, secondBody, rectangleCategory);
fallingS = nodeFromBody(firstBody, secondBody, fallingSquareCategory);
if (R1 && fallingS && radBool == 1)
{
[fallingS removeFromParent];
}
}
I believe your issue is the "begin" part of didBeginContact. It only gets called the first time they contact and not every loop. Because the bool was not set to YES when they first contacted it will never be evaluated again.
I believe I ran into this issue once before and the solution was to create a new physical body when you touch it. This "should" trigger didBeginContact the next go around. You might also be able to change a property on the physical body, but if I recall correctly I didn't get that to work and had to init a new physical body.
For example try updating your touchesBegan with this
touchesBeganMethod
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if ([node.name isEqualToString:#"rect"])
{
radBool = 1;
node.physicsBody = nil;
node.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:rectangle.size];
node.physicsBody.categoryBitMask = rectangleCategory;
node.physicsBody.contactTestBitMask = fallingSquareCategory;
node.physicsBody.collisionBitMask = 0;
}
}
Hope that works for you.

sprite kit: verify if touch is inside a node

I'm trying to figure out how to detect if I touch a node in sprite kit. I thought it was function like this in UIView:
[myView pointInside:point withEvent:nil];
But so far I can not have found an alternative to this. What I'm trying to accomplish is to know I have touch the sprite node in the screen.
I'll really appreciate if you can help me to I acomplish this
Here is what I have in my code. I'm adding animated node:
-(void)addMyNodeAnimated
{
NSMutableArray *myNodeArray = [NSMutableArray array];
NSArray *animatedFrames = [NSArray new];
SKTextureAtlas *AnimatedAtlas = [SKTextureAtlas atlasNamed:#"pc2"];
int numImages = (int)AnimatedAtlas.textureNames.count;
for (int i=1; i <= numImages; i++) {
NSString *textureName = [NSString stringWithFormat:#"%#-%d", #"pc2", i];
SKTexture *temp = [AnimatedAtlas textureNamed:textureName];
[myNodeArray addObject:temp];
}
animatedFrames = myNodeArray;
SKTexture *temp = animatedFrames[0];
SKSpriteNode *animationNode = [SKSpriteNode spriteNodeWithTexture:temp];
animationNode.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
animationNode.userInteractionEnabled = YES;
animationNode.name = #"AnimationNode";
[self addChild:animationNode];
[animationNode runAction:[SKAction repeatActionForever:
[SKAction animateWithTextures:animatedFrames
timePerFrame:0.1f
resize:NO
restore:YES]] withKey:#"AnimationRuning"];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint _touchLocation = [[touches anyObject] locationInNode:self];
SKNode *node = [self nodeAtPoint:_touchLocation];
if (node != nil)
{
NSLog(#"node name %#", node.name);
}
}
When I touch the node in the screen the node returns null.
Any of know why is this?
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if ([node.name isEqualToString:#"yourSpriteName"] && [node.name isEqualToString:#"yourEffectName"]) {
//Whatever you want.
}
}

iOS How to draw a stroke with an outline

I am looking for an output as in this image Expected Result
I need an outline to my stroke. My code is as follows
- (void)awakeFromNib {
self.strokeArray = [NSMutableArray array];
self.layerIndex = 0;
self.isSolid = false;
self.path = [[UIBezierPath alloc] init];
self.innerPath = [[UIBezierPath alloc] init];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:self];
[self.path moveToPoint:p];
[self.innerPath moveToPoint:p];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:self];
[self.path addLineToPoint:p];
[self.innerPath addLineToPoint:p];
[self setNeedsDisplay];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:self];
[self.path addLineToPoint:p];
[self.innerPath addLineToPoint:p];
[self drawBitmap];
[self setNeedsDisplay];
[self.path removeAllPoints];
[self.innerPath removeAllPoints];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesEnded:touches withEvent:event];
}
- (void)drawRect:(CGRect)rect
{
[self.incrementalImage drawInRect:rect];
[self.brushColor setStroke];
self.path.lineWidth = self.brushWidth;
if(self.isEraser)
[self.path strokeWithBlendMode:kCGBlendModeClear alpha:0.0];
else
[self.path stroke];
self.innerPath.lineWidth = self.brushWidth - 10;
[[UIColor clearColor] setStroke];
[self.innerPath strokeWithBlendMode:kCGBlendModeClear alpha:1.0];
}
- (void)drawBitmap
{
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();
if (!self.incrementalImage)
{
CGContextClearRect(context, CGRectMake(0,0,self.bounds.size.width,self.bounds.size.height));
}
[self.incrementalImage drawAtPoint:CGPointZero];
[self.brushColor setStroke];
self.path.lineWidth = self.brushWidth;
if(self.isEraser)
[self.path strokeWithBlendMode:kCGBlendModeClear alpha:0.0];
else
[self.path stroke];
self.innerPath.lineWidth = self.brushWidth - 10;
[[UIColor clearColor] setStroke];
[self.innerPath strokeWithBlendMode:kCGBlendModeClear alpha:1.0];
self.incrementalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
On screen what i get is as per this image, Actual Result
I understand that blend mode 'clear' gives an eraser effect. What i want is that the stroke should have a solid outline on the sides and be clear in the middle. It should not blend into the path right below it.The path below it should still be visible.
How can i achieve this result?
Have a look at this question: Generate a CGPath from another path's line width outline
I guess that's what you need: creating a polygon of the line and stroke that instead of the line. Use CGPathCreateCopyByStrokingPath to get a path of the polygon and stroke it.
OK, since CGPathCreateCopyByStrokingPath seems to be a bit buggy, you could create your own implementation. Something like the following algorithm, which assumes you have a NSArray of CGPoint packed in NSValue objects.
It works pretty well until you start adding short overlapping lines which could of course easily happen while drawing. You could reduce this effect by only adding points in touchesMoved that have a larger distance (lineWidth/2?) to the previous added point. Another drawback is that the lines are simply straight (no kCGLineJoinRound or kCGLineCapRound) but maybe you could adjust the algorithm to do that.
+ (UIBezierPath*)polygonForLine:(NSArray *)points withLineWidth:(CGFloat)lineWidth{
UIBezierPath *path = [UIBezierPath bezierPath];
//stores the starting point to close the path
CGPoint startPoint;
//get the points to a c-array for easier access
CGPoint cpoints[points.count];
int numPoints = 0;
for(NSValue *v in points){
cpoints[numPoints++] = [v CGPointValue];
}
//store the last intersection to apply it for the next segement
BOOL hasIntersection = NO;
CGPoint intersectionPoint;
for (int i=0;i<numPoints-1;i++){
//get the current line segment
CGPoint p1 = cpoints[i];
CGPoint p2 = cpoints[i+1];
CGPoint l1p1,l1p2;
getOffsetLineSegmentForPoints(p1,p2,lineWidth,&l1p1,&l1p2);
//if there had been an intersection with the previous segement, start here to get a nice outline
if(hasIntersection){
l1p1 = intersectionPoint;
}
//is there a next segment?
if(i+2<numPoints){
//get the next line segment
p1 = cpoints[i+1];
p2 = cpoints[i+2];
CGPoint l2p1,l2p2;
getOffsetLineSegmentForPoints(p1,p2,lineWidth,&l2p1,&l2p2);
//calculate the intersection point with the current line segment
hasIntersection = getLineIntersection(l1p1, l1p2, l2p1, l2p2, &intersectionPoint);
//if they intersect, the current linesegment has to end here to get a nice outline
if(hasIntersection){
l1p2 = intersectionPoint;
}
}
//write the current linesegment to the path
if(i==0){
//first point, move to it and store it for closing the path later on
startPoint = l1p1;
[path moveToPoint:startPoint];
}else{
[path addLineToPoint:l1p1];
}
[path addLineToPoint:l1p2];
}
//now do the same for the other side of the future polygon
hasIntersection = NO;//reset intersections
for (int i=numPoints-1;i>0;i--){
//get the current line segment
CGPoint p1 = cpoints[i];
CGPoint p2 = cpoints[i-1];
CGPoint l1p1,l1p2;
getOffsetLineSegmentForPoints(p1,p2,lineWidth,&l1p1,&l1p2);
//if there had been an intersection with the previous segement, start here to get a nice outline
if(hasIntersection){
l1p1 = intersectionPoint;
}
//is there a next segment?
if(i-2>=0){
//get the next line segment
p1 = cpoints[i-1];
p2 = cpoints[i-2];
CGPoint l2p1,l2p2;
getOffsetLineSegmentForPoints(p1,p2,lineWidth,&l2p1,&l2p2);
//calculate the intersection point with the current line segment
hasIntersection = getLineIntersection(l1p1, l1p2, l2p1, l2p2, &intersectionPoint);
//if they intersect, the current linesegment has to end here to get a nice outline
if(hasIntersection){
l1p2 = intersectionPoint;
}
}
//write the current linesegment to the path
[path addLineToPoint:l1p1];
[path addLineToPoint:l1p2];
}
//close the path
[path addLineToPoint:startPoint];
//we're done
return path;
}
void getOffsetLineSegmentForPoints(CGPoint p1, CGPoint p2, CGFloat lineWidth, CGPoint *linep1, CGPoint *linep2){
CGPoint offset = CGPointSub(p2, p1);
offset = CGPointNorm(offset);
offset = CGPointOrthogonal(offset);
offset = CGPointMultiply(offset, lineWidth/2);
(*linep1) = CGPointAdd(p1, offset);
(*linep2) = CGPointAdd(p2, offset);
}
CGPoint CGPointSub(CGPoint p1, CGPoint p2){
return CGPointMake(p1.x-p2.x, p1.y-p2.y);
}
CGPoint CGPointAdd(CGPoint p1, CGPoint p2){
return CGPointMake(p1.x+p2.x, p1.y+p2.y);
}
CGFloat CGPointLength(CGPoint p){
return sqrtf(powf(p.x,2)+powf(p.y,2));
}
CGPoint CGPointNorm(CGPoint p){
CGFloat length = CGPointLength(p);
if(length==0)
return CGPointZero;
return CGPointMultiply(p, 1/length);
}
CGPoint CGPointMultiply(CGPoint p, CGFloat f){
return CGPointMake(p.x*f, p.y*f);
}
CGPoint CGPointOrthogonal(CGPoint p){
return CGPointMake(p.y, -p.x);
}
BOOL getLineIntersection(CGPoint l1p1, CGPoint l1p2, CGPoint l2p1,
CGPoint l2p2, CGPoint *intersection)
{
CGPoint s1 = CGPointSub(l1p2, l1p1);
CGPoint s2 = CGPointSub(l2p2, l2p1);
float determinant = (-s2.x * s1.y + s1.x * s2.y);
if(determinant==0)
return NO;
CGPoint l2p1l1p1 = CGPointSub(l1p1, l2p1);
float s, t;
s = (-s1.y * l2p1l1p1.x + s1.x * l2p1l1p1.y) / determinant;
t = ( s2.x * l2p1l1p1.y - s2.y * l2p1l1p1.x) / determinant;
if (s >= 0 && s <= 1 && t >= 0 && t <= 1){
if (intersection != NULL){
(*intersection).x = l1p1.x + (t * s1.x);
(*intersection).y = l1p1.y + (t * s1.y);
}
return YES;
}
return NO;
}

Resources