Drawing Arrowhead curve with words (Objective-c cocos2D) - cocos2d-iphone

I'm trying to draw an arrowhead-curve using Fibonacci-esque words. I may use method calls instead of building onto a string later on, but for now I want to preserve the string.
// create string. Initially set to "A"
NSMutableString *s1 = [[NSMutableString alloc] init];
[s1 setString:#"A"];
// loop through and replace A and B with the following strings. Toned down iterations to 5 here
for(int i=0; i<5; ++i){
[s1 replaceOccurrencesOfString:#"A"
withString:#"+B-A-B+"
options:NSLiteralSearch
range:NSMakeRange(0, s1.length)];
[s1 replaceOccurrencesOfString:#"B"
withString:#"-A+B+A-"
options:NSLiteralSearch
range:NSMakeRange(0, s1.length)];
}
// set line color, thickness
ccDrawColor4F(0.8, 1.0, 0.76, 1.0);
glLineWidth(1.0f);
float angle = 0;
float travelDist = 1; // distance in pixels the line is drawn. Can be changed to whatever
CGPoint p = CGPointMake(300,100);
for(int i = 0; i < [s1 length]; i++){
if([[NSString stringWithFormat:#"%c",[s1 characterAtIndex:i]] isEqualToString:#"+"]){ // turn right
angle += 60;
}else if([[NSString stringWithFormat:#"%c",[s1 characterAtIndex:i]] isEqualToString:#"-"]){ // turn left
angle -= 60;
}else{ // any other character, draw line
float cosAngle = cosf(CC_DEGREES_TO_RADIANS(angle));
float newDist = travelDist * cosAngle;
float sinAngle = sinf(CC_DEGREES_TO_RADIANS(angle));
float newDist2 = travelDist *sinAngle;
ccDrawLine( ccp(p.x, p.y), ccp(p.x + newDist, p.y + newDist2) );
p = CGPointMake(p.x + newDist, p.y + newDist2);
}
}
I've read up on several sites about arrowhead curves, and the rules they must follow. It seems like I should be doing the right thing, but it doesn't turn out quite right. I get something representing a Sierpinski's triangle, but not a proper arrowhead curve.
You may not have to know Objective-c/Cocos2d to answer this, as I'm probably just doing something logistically incorrect.

I need to create a new temporary string based on the current string, and go through one character at a time, and make the string the temporary one at the end of each iteration:
NSMutableString *s1 = [[NSMutableString alloc] init];
[s1 setString:#"A"];
NSMutableString *sTemp = [[NSMutableString alloc] init];
[sTemp setString:#""];
for(int i=0; i<6; ++i){
for(int j = 0; j < [s1 length]; j++){
unichar character = [s1 characterAtIndex:j];
if(character == 'A'){
[sTemp appendString:#"B-A-B"];
}
else if(character == 'B'){
[sTemp appendString:#"A+B+A"];
}else{
[sTemp appendString:[NSString stringWithFormat:#"%C",character]];
}
}
[s1 setString:sTemp];
[sTemp setString:#""];
}

Related

Outline of pixels after detecting object (without convex hull)

The idea is to use grabcut (OpenCV) to detect the image inside a rectangle and create a geometry with Direct2D.
My test image is this:
After performing the grab cut, resulting in this image:
the idea is to outline it. I can use an opacity brush to exclude it from the background but I want to use a geometric brush in order to be able to append/widen/combine geometries on it like all other selections in my editor (polygon, lasso, rectangle, etc).
If I apply the convex hull algorithm to the points, I get this:
Which of course is not desired for my case. How do I outline the image?
After getting the image from the grabcut, I keep the points based on luminance:
DWORD* pixels = ...
for (UINT y = 0; y < he; y++)
{
for (UINT x = 0; x < wi; x++)
{
DWORD& col = pixels[y * wi + x];
auto lumthis = lum(col);
if (lumthis > Lum_Threshold)
{
points.push_back({x,y});
}
}
}
Then I sort the points on Y and X:
std::sort(points.begin(), points.end(), [](D2D1_POINT_2F p1, D2D1_POINT_2F p2) -> bool
{
if (p1.y < p2.y)
return true;
if ((int)p1.y == (int)p2.y && p1.x < p2.x)
return true;
return false;
});
Then, for each line (traversing the above point array from top Y to bototm Y) I create "groups" for each line:
struct SECTION
{
float left = 0, right = 0;
};
auto findgaps = [](D2D1_POINT_2F* p,size_t n) -> std::vector<SECTION>
{
std::vector<SECTION> j;
SECTION* jj = 0;
for (size_t i = 0; i < n; i++)
{
if (i == 0)
{
SECTION jp;
jp.left = p[i].x;
jp.right = p[i].x;
j.push_back(jp);
jj = &j[j.size() - 1];
continue;
}
if ((p[i].x - jj->right) < 1.5f)
{
jj->right = p[i].x;
}
else
{
SECTION jp;
jp.left = p[i].x;
jp.right = p[i].x;
j.push_back(jp);
jj = &j[j.size() - 1];
}
}
return j;
};
I'm stuck at this point. I know that from an arbitrary set of points many polygons are possible, but in my case the points have defined what's "left" and what's "right". How would I proceed from here?
For anyone interested, the solution is OpenCV contours. Working example here.

How to get the left chain of points of a polygon?

I am trying to get the left polygonal chain given a set of consecutive points. (NOTE: edges are non-intersecting.)
Image 1. Sample polygon and its bound.
What I did was:
Get the minY, maxY and minX. (Bound.)
Find the point that contains minY (or maxY) then save it as the first point.
Save any points until point with minY or maxY is found while checking for point with minX.
If the same Y is found first, save it as the new first point and repeat from #3.
If other Y is found first and the saved points has minX, this is the chain. Otherwise, save as the new first point and repeat from #3.
Image 2. The left chain of points.
But using this steps might give wrong result for some polygon, like this:
Since one point is (minX, maxY), either of the side will be returned.
EDIT:
With the idea of the left-bottom- and left-top-most points, here is the current code that I am using:
Get the min (left-bottom-most) and max (left-top-most) point.
std::vector<Coord> ret;
size_t i = 0;
Coord minCoord = poly[i];
Coord maxCoord = poly[i];
size_t minIdx = -1;
size_t maxIdx = -1;
size_t cnt = poly.size();
i++;
for (; i < cnt; i++)
{
Coord c = poly[i];
if (c.y < minCoord.y) // new bottom
{
minCoord = c;
minIdx = i;
}
else if (c.y == minCoord.y) // same bottom
{
if (c.x < minCoord.x) // left most
{
minCoord = c;
minIdx = i;
}
}
if (c.y > maxCoord.y) // new top
{
maxCoord = c;
maxIdx = i;
}
else if (c.y == maxCoord.y) // same top
{
if (c.x < maxCoord.x) // left most
{
maxCoord = c;
maxIdx = i;
}
}
}
Get the points connected to the max point.
i = maxIdx;
Coord mid = poly[i];
Coord ray1 = poly[(i + cnt - 1) % cnt];
Coord ray2 = poly[(i + 1) % cnt];
Get which has smallest angle. This will be the path we will follow.
double rad1 = Pts2Rad(mid, ray1);
double rad2 = Pts2Rad(mid, ray2);
int step = 1;
if (rad1 < rad2)
step = cnt - 1;
Save the points.
while (i != minIdx)
{
ret.push_back(poly[i]);
i = (i + step) % cnt;
}
ret.push_back(poly[minIdx]);
To be specific, I am assuming that no vertex is duplicated and define the "left chain" as the sequence of vertices from the original polygon loop that goes from the leftmost vertex in the top side of the bounding box, to the leftmost vertex in the bottom side of the bounding box. [In case the top and bottom sides coincide, these two vertices also coincide; I leave it to you what to return in this case.]
To obtain these, you can scan all vertices and keep the left-topmost so far and left-bottommost so far. Then compare to the next vertex. If above the left-topmost, becomes the new lef-topmost. If at the same level and to the left, becomes the new left-topmost. Similarly for the left-bottommost.

How do we enumerate and modify positions array of CCsprite inside Update method?

How do we enumerate and alter our object's position (contained in array) for each delta time?
I put some CCsprite objects inside array, then I displayed them in scene, but also I wanted to make them move with modifying update method, I failed on last part.
How do I get around this ?
#implementation GameScene
{
Hunter *_hunter;
Bird *_bird;
NSMutableArray *_arrayOfBirds;
}
-(void)update:(CCTime)delta{
CGSize viewSize = [CCDirector sharedDirector].viewSize;
float birdSpeed = 50;
for (Bird *birds in _arrayOfBirds) {
if (birds.position.x < 0) {
birds.flipX = YES;
}
if (birds.position.x > viewSize.width) {
birds.flipX = NO;
}
float distanceToMove = birdSpeed * delta;
float direction = birds.flipX ? 1 : -1;
float newX = birds.position.x + direction * distanceToMove;
float newY = birds.position.y;
birds.position = ccp(newX, newY);
}
}
-(void)addBird{
CGSize viewSize = [CCDirector sharedDirector].viewSize;
for (int i=0; i < 4; i++) {
_bird = [[Bird alloc]initWithBirdType:(i)];
_bird.position = ccp(viewSize.width * 0.5f + 30 * i , viewSize.height * 0.9f - 15* i);
[self addChild:_bird];
[_arrayOfBirds addObject:_bird];
}
}
You forgot to initialize your array
here (assuming ARC)
-(id) init {
if(self=[super init]) {
_arrayOfBirds = [[NSMutableArray alloc] init];
// the rest
}
return self;
}

How make a Rect for tiles from a Tiled Map

For my collision detection I need to check of the ball rect intersects any of the wall rects. Right now I have it working but its checking to see if the ball's position is at one of the tile's GID, using this.
-(void) checkHits:(CGPoint)position {
CGPoint tileCoord = [self tileCoordForPosition:position];
int tileGid = [levelLayer tileGIDAt:tileCoord];
//NSLog(#"%g",tileRect.origin);
if (tileGid) {
NSDictionary *properties = [level propertiesForGID:tileGid];
if (properties) {
NSString *collision = [properties valueForKey:#"break"];
if (collision && [collision compare:#"True"] == NSOrderedSame) {
//for blocks
//[[SimpleAudioEngine sharedEngine] playEffect:#"hit.caf"];
[levelLayer removeTileAt:tileCoord];
velocity.y *= -1;
}
if (collision && [collision compare:#"False"] == NSOrderedSame) {
//for edges
//[[SimpleAudioEngine sharedEngine] playEffect:#"hit.caf"];
velocity.y *= -1;
}
}
}
}
I need to know how to change this to checking to see if the balls rect/boundingbox intersects with any of the tiles rects/boundingboxex(and how to get the tiles rect/boundingbox in the first place) that have the property break.
P.S. I'm using the Tiled map editor.
Figured this out a little while ago:
CCSprite *tile;
for (int i = 0; i < level.contentSize.width/level.tileSize.width; i ++)
for (int j = 0; j < level.contentSize.height/level.tileSize.height; j ++){
tile = [levelLayer tileAt:ccp(i,j)];
if (CGRectIntersectsRect(ball.boundingBox, tile.boundingBox)) {
//Do whatever...
}
}
}
I recommend having a collide layer to make map making easier.

How to draw a curved line using ccBezier?

I drew a line with -(void)draw method:
-(void)draw // code for line draw
{
glEnable(GL_LINE_SMOOTH);
CGPoint start;
start.x = 50;
start.y = 50;
CGPoint end;
end.x = 50;
end.y = 200;
if (pointOne.x>300){
pointOne.x = 300;
}
if (pointOne.y>200){
pointOne.y = 200;
}
ccDrawLine(start, pointOne);//get a line
[self Bezier:location.x:location.y:pointOne.x:pointOne.y];
}
and now I want to curve this line through Bezier in cocos2d. When I move finger that time line should draw the curve.
Bezier Code is:
- (void) Bezier:(NSInteger) CP_x:(NSInteger) CP_y:(NSInteger) end_x:(NSInteger) end_y
{
CGPoint start;
start.x = 50;
start.y = 50;
ccBezierConfig bezier;
bezier.controlPoint_1 = ccp(CP_x, CP_y);
bezier.controlPoint_2 = ccp(CP_x,CP_y);
bezier.endPosition = ccp(end_x,end_y);
}
How can I implement this line in bezier?
try this.
CCDrawBezier in last of your -(void)Bezier methord
ccDrawCubicBezier(StartPoint, controlPoint_1, controlPoint_2, EndPoint,NSInteger);
This is a method is wrote to my game.
//Bezier calculation on multiple points
//Can be set to any number of points
//The t parameter is the time 0 = start point -> 1 = end point.
//Made by Sebastian Winbladh
-(CGPoint)getBezerAtTime:(float)t array:(NSArray*)a{
int count = [a count];
float xPoints[count],yPoints[count];
int c=0;
//Makeup an array for our points
for(int i=0;i<count;i++){
CGPoint p = CGPointMake([[[a objectAtIndex:i] objectAtIndex:0] floatValue], [[[a objectAtIndex:i] objectAtIndex:1] floatValue]);
xPoints[i] = p.x;
yPoints[i] = p.y;
c++;
}
//Calculate our bezier curve here
while(c != 0){
for(int i=0;i<c-1;i++){
CGPoint p0 = CGPointMake(xPoints[i], yPoints[i]);
CGPoint p1 = CGPointMake(xPoints[i+1], yPoints[i+1]);
float dx = p1.x - p0.x;
float dy = p1.y - p0.y;
dx = p0.x + (dx * t);
dy = p0.y + (dy * t);
xPoints[i] = dx;
yPoints[i] = dy;
}c--;
}
return CGPointMake(xPoints[0], yPoints[0]);
}