Drawing a ruler in objective c iPhone - iphone

I am trying to create a dynamic ruler using code from this post of Brad Larson
NSInteger majorTickInterval = 5;
NSInteger totalTravelRangeInMicrons = 1000;
NSInteger minorTickSpacingInMicrons = 50;
CGFloat currentHeight = 100;
int leftEdgeForTicks = 10;
int majorTickLength = 15;
int minorTickLength = 10;
NSInteger minorTickCounter = majorTickInterval;
NSInteger totalNumberOfTicks = totalTravelRangeInMicrons / minorTickSpacingInMicrons;
CGFloat minorTickSpacingInPixels = currentHeight / (CGFloat)totalNumberOfTicks;
CGContextSetStrokeColorWithColor(context, [[UIColor blackColor] CGColor]);
for (NSInteger currentTickNumber = 0; currentTickNumber < totalNumberOfTicks; currentTickNumber++)
{
CGContextMoveToPoint(context, leftEdgeForTicks + 0.5, round(currentTickNumber * minorTickSpacingInPixels) + 0.5);
minorTickCounter++;
if (minorTickCounter >= majorTickInterval)
{
CGContextAddLineToPoint(context, round(leftEdgeForTicks + majorTickLength) + 7**.5, round(currentTickNumber * minorTickSpacingInPixels) + 0.5);
minorTickCounter = 0;
}
else
{
CGContextAddLineToPoint(context, round(leftEdgeForTicks + minorTickLength) + 0.5, round(currentTickNumber * minorTickSpacingInPixels) + 0.5);
}
}
CGContextStrokePath(context);
But the issue is that it is creating ticks vertically not horizontally as in below screenshot:
While I want to draw a ruler like this:
Also it is not giving me more than 25 ticks, I have played with the code but still unsuccessful.
Any guidance how can I resolve this issue.

Here is an implementation, from the top of my head... I think it is important to keep it readable.
CGFloat leftMargin= 10;
CGFloat topMargin = 10;
CGFloat height = 30;
CGFloat width = 200;
CGFloat minorTickSpace = 10;
int multiple = 5; // number of minor ticks per major tick
CGFloat majorTickLength = 20; // must be smaller or equal height,
CGFloat minorTickLength = 10; // must be smaller than majorTickLength
CGFloat baseY = topMargin + height;
CGFloat minorY = baseY - minorTickLength;
CGFloat majorY = baseY - majorTickLength;
CGFloat majorTickSpace = minorTickSpace * multiple;
int step = 0;
for (CGFloat x = leftMargin; x <= leftMargin + width, x += minorTickLength) {
CGContextMoveToPoint(context, x, baseY);
CGFloat endY = (step*multiple*minorTickLength == x) ? majorY : minorY;
CGContextAddLineToPoint(context, x, endY);
step++; // step contains the minorTickCount in case you want to draw labels
}
CGContextStrokePath(context);

Related

How to draw dots in a semi - circle pattern

How can I draw dots in semi circular pattern in iphone programmatically?
I did using the below code
CGContextRef ctx = UIGraphicsGetCurrentContext();
float angle = 0;
float centerX = self.frame.size.width/2;
float centerY = self.frame.size.width/2;
float startX = 0.0;
float startY = 0.0;
for (int i = 0; i < 8 ; i++) {
startX = centerX + cos(angle) * (radius + 50) - 5 ;
startY = centerY + sin(angle) * (radius + 50 ) - 5;
CGContextFillEllipseInRect(ctx, CGRectMake(startX, startY, 5, 5));
[[UIColor blackColor] setStroke];
angle-= M_PI/7;
}
you can like this way Quartz_2D:-
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 20.0);
CGContextSetStrokeColorWithColor(context,
[UIColor blueColor].CGColor);
CGFloat dashArray[] = {2,6,4,2};
CGContextSetLineDash(context, 3, dashArray, 4);
CGContextMoveToPoint(context, 10, 200);
CGContextAddQuadCurveToPoint(context, 150, 10, 300, 200);
CGContextStrokePath(context);
}
check out bellow all drawing examples :-
http://www.techotopia.com/index.php/An_iOS_5_iPhone_Graphics_Drawing_Tutorial_using_Quartz_2D

Detect paper as series of points with OpenCV

I'm attempting to detect a piece of paper in a photo on the iPhone using OpenCV. I'm using the code from this question: OpenCV C++/Obj-C: Detecting a sheet of paper / Square Detection
Here's the code:
- (void)findEdges {
image = [[UIImage imageNamed:#"photo.JPG"] retain];
Mat matImage = [image CVMat];
find_squares(matImage, points);
UIImageView *imageView = [[[UIImageView alloc] initWithImage:image] autorelease];
[imageView setFrame:CGRectMake(0.0f, 0.0f, self.frame.size.width, self.frame.size.height)];
[self addSubview:imageView];
[imageView setAlpha:0.3f];
}
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 0.8);
CGFloat scaleX = self.frame.size.width / image.size.width;
CGFloat scaleY = self.frame.size.height / image.size.height;
// Draw the detected squares.
for( vector<vector<cv::Point> >::const_iterator it = points.begin(); it != points.end(); it++ ) {
vector<cv::Point> square = *it;
cv::Point p1 = square[0];
cv::Point p2 = square[1];
cv::Point p3 = square[2];
cv::Point p4 = square[3];
CGContextBeginPath(context);
CGContextMoveToPoint(context, p1.x * scaleX, p1.y * scaleY); //start point
CGContextAddLineToPoint(context, p2.x * scaleX, p2.y * scaleY);
CGContextAddLineToPoint(context, p3.x * scaleX, p3.y * scaleY);
CGContextAddLineToPoint(context, p4.x * scaleX, p4.y * scaleY); // end path
CGContextClosePath(context);
CGContextSetLineWidth(context, 4.0);
CGContextStrokePath(context);
}
}
double angle( cv::Point pt1, cv::Point pt2, cv::Point pt0 ) {
double dx1 = pt1.x - pt0.x;
double dy1 = pt1.y - pt0.y;
double dx2 = pt2.x - pt0.x;
double dy2 = pt2.y - pt0.y;
return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
}
void find_squares(Mat& image, vector<vector<cv::Point> >& squares) {
// blur will enhance edge detection
Mat blurred(image);
medianBlur(image, blurred, 9);
Mat gray0(blurred.size(), CV_8U), gray;
vector<vector<cv::Point> > contours;
// find squares in every color plane of the image
for (int c = 0; c < 3; c++)
{
int ch[] = {c, 0};
mixChannels(&blurred, 1, &gray0, 1, ch, 1);
// try several threshold levels
const int threshold_level = 2;
for (int l = 0; l < threshold_level; l++)
{
// Use Canny instead of zero threshold level!
// Canny helps to catch squares with gradient shading
if (l == 0)
{
Canny(gray0, gray, 10, 20, 3); //
// Dilate helps to remove potential holes between edge segments
dilate(gray, gray, Mat(), cv::Point(-1,-1));
}
else
{
gray = gray0 >= (l+1) * 255 / threshold_level;
}
// Find contours and store them in a list
findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
// Test contours
vector<cv::Point> approx;
for (size_t i = 0; i < contours.size(); i++)
{
// approximate contour with accuracy proportional
// to the contour perimeter
approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true);
// Note: absolute value of an area is used because
// area may be positive or negative - in accordance with the
// contour orientation
if (approx.size() == 4 &&
fabs(contourArea(Mat(approx))) > 1000 &&
isContourConvex(Mat(approx)))
{
double maxCosine = 0;
for (int j = 2; j < 5; j++)
{
double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1]));
maxCosine = MAX(maxCosine, cosine);
}
if (maxCosine < 0.3)
squares.push_back(approx);
}
}
}
}
}
Here's the input image:
Here's the result:
What am I doing wrong?

iPhone paint bucket

I am working on implementing a flood-fill paint-bucket tool in an iPhone app and am having some trouble with it. The user is able to draw and I would like the paint bucket to allow them to tap a spot and fill everything of that color that is connected.
Here's my idea:
1) Start at the point the user selects
2) Save points checked to a NSMutableArray so they don't get re-checked
3) If the pixel color at the current point is the same as the original clicked point, save to an array to be changed later
4) If the pixel color at the current point is different than the original, return. (boundary)
5) Once finished scanning, go through the array of pixels to change and set them to the new color.
But this is not working out so far. Any help or knowledge of how to do this would be greatly appreciated! Here is my code.
-(void)flood:(int)x:(int)y
{
//NSLog(#"Flood %i %i", x, y);
CGPoint point = CGPointMake(x, y);
NSValue *value = [NSValue valueWithCGPoint:point];
//Don't repeat checked pixels
if([self.checkedFloodPixels containsObject:value])
{
return;
}
else
{
//If not checked, mark as checked
[self.checkedFloodPixels addObject:value];
//Make sure in bounds
if([self isOutOfBounds:x:y] || [self reachedStopColor:x:y])
{
return;
}
//Go to adjacent points
[self flood:x+1:y];
[self flood:x-1:y];
[self flood:x:y+1];
[self flood:x:y-1];
}
}
- (BOOL)isOutOfBounds:(int)x:(int)y
{
BOOL outOfBounds;
if(y > self.drawImage.frame.origin.y && y < (self.drawImage.frame.origin.y + self.drawImage.frame.size.height))
{
if(x > self.drawImage.frame.origin.x && x < (self.drawImage.frame.origin.x + self.drawImage.frame.size.width))
{
outOfBounds = NO;
}
else
{
outOfBounds = YES;
}
}
else
{
outOfBounds = YES;
}
if(outOfBounds)
NSLog(#"Out of bounds");
return outOfBounds;
}
- (BOOL)reachedStopColor:(int)x:(int)y
{
CFDataRef theData = CGDataProviderCopyData(CGImageGetDataProvider(self.drawImage.image.CGImage));
const UInt8 *pixelData = CFDataGetBytePtr(theData);
int red = 0;
int green = 1;
int blue = 2;
//RGB for point being checked
float newPointR;
float newPointG;
float newPointB;
//RGB for point initially clicked
float oldPointR;
float oldPointG;
float oldPointB;
int index;
BOOL reachedStopColor = NO;
//Format oldPoint RBG - pixels are every 4 bytes so round to 4
index = lastPoint.x * lastPoint.y;
if(index % 4 != 0)
{
index -= 2;
index /= 4;
index *= 4;
}
//Get into 0.0 - 1.0 value
oldPointR = pixelData[index + red];
oldPointG = pixelData[index + green];
oldPointB = pixelData[index + blue];
oldPointR /= 255.0;
oldPointG /= 255.0;
oldPointB /= 255.0;
oldPointR *= 1000;
oldPointG *= 1000;
oldPointB *= 1000;
int oldR = oldPointR;
int oldG = oldPointG;
int oldB = oldPointB;
oldPointR = oldR / 1000.0;
oldPointG = oldG / 1000.0;
oldPointB = oldB / 1000.0;
//Format newPoint RBG
index = x*y;
if(index % 4 != 0)
{
index -= 2;
index /= 4;
index *= 4;
}
newPointR = pixelData[index + red];
newPointG = pixelData[index + green];
newPointB = pixelData[index + blue];
newPointR /= 255.0;
newPointG /= 255.0;
newPointB /= 255.0;
newPointR *= 1000;
newPointG *= 1000;
newPointB *= 1000;
int newR = newPointR;
int newG = newPointG;
int newB = newPointB;
newPointR = newR / 1000.0;
newPointG = newG / 1000.0;
newPointB = newB / 1000.0;
//Check if different color
if(newPointR < (oldPointR - 0.02f) || newPointR > (oldPointR + 0.02f))
{
if(newPointG < (oldPointG - 0.02f) || newPointG > (oldPointG + 0.02f))
{
if(newPointB < (oldPointB - 0.02f) || newPointB > (oldPointB + 0.02f))
{
reachedStopColor = YES;
NSLog(#"Different Color");
}
else
{
NSLog(#"Same Color3");
NSNumber *num = [NSNumber numberWithInt:index];
[self.pixelsToChange addObject:num];
}
}
else
{
NSLog(#"Same Color2");
NSNumber *num = [NSNumber numberWithInt:index];
[self.pixelsToChange addObject:num];
}
}
else
{
NSLog(#"Same Color1");
NSNumber *num = [NSNumber numberWithInt:index];
[self.pixelsToChange addObject:num];
}
CFRelease(theData);
if(reachedStopColor)
NSLog(#"Reached stop color");
return reachedStopColor;
}
-(void)fillAll
{
CGContextRef ctx;
CGImageRef imageRef = self.drawImage.image.CGImage;
NSUInteger width = CGImageGetWidth(imageRef);
NSUInteger height = CGImageGetHeight(imageRef);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
unsigned char *rawData = malloc(height * width * 4);
NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(rawData, width, height,
bitsPerComponent, bytesPerRow, colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGContextRelease(context);
int red = 0;
int green = 1;
int blue = 2;
int index;
NSNumber *num;
for(int i = 0; i < [self.pixelsToChange count]; i++)
{
num = [self.pixelsToChange objectAtIndex:i];
index = [num intValue];
rawData[index + red] = (char)[[GameManager sharedManager] RValue];
rawData[index + green] = (char)[[GameManager sharedManager] GValue];
rawData[index + blue] = (char)[[GameManager sharedManager] BValue];
}
ctx = CGBitmapContextCreate(rawData,
CGImageGetWidth( imageRef ),
CGImageGetHeight( imageRef ),
8,
CGImageGetBytesPerRow( imageRef ),
CGImageGetColorSpace( imageRef ),
kCGImageAlphaPremultipliedLast );
imageRef = CGBitmapContextCreateImage (ctx);
UIImage* rawImage = [UIImage imageWithCGImage:imageRef];
CGContextRelease(ctx);
self.drawImage.image = rawImage;
free(rawData);
}
so i found this (i know the question might be irrelevant now but for people who are still looking for something like this it's not ) :
to get color at pixel from context (modified code from here) :
- (UIColor*) getPixelColorAtLocation:(CGPoint)point {
UIColor* color;
CGContextRef cgctx = UIGraphicsGetCurrentContext();
unsigned char* data = CGBitmapContextGetData (cgctx);
if (data != NULL) {
int offset = 4*((ContextWidth*round(point.y))+round(point.x)); //i dont know how to get ContextWidth from current context so i have it as a instance variable in my code
int alpha = data[offset];
int red = data[offset+1];
int green = data[offset+2];
int blue = data[offset+3];
color = [UIColor colorWithRed:(red/255.0f) green:(green/255.0f) blue:(blue/255.0f) alpha:(alpha/255.0f)];
}
if (data) { free(data); }
return color;
}
and the fill algorithm: is here
This is what i'm using but the fill itself is quite slow compared to CGPath drawing styles. Tho if you're rendering offscreen and/or you fill it dynamically like this it looks kinda cool :

How to define a struct correctly

I have a struct where I define the size (width, height) of a square, and I don't know why the code doesn't work well. Here's the code that I'm using:
.h
struct size{
int width;
int height;
};
.m
struct size a;
a.width = 508;
a.height = 686;
// I use it here.
Any ideas?
If you want to use Apple provided types, you have:
CGSize for sizes (with width and height)
CGPoint for locations (with x and y)
and CGRect, which combines the two.
Example usage:
CGPoint p;
CGSize s;
CGRect r;
p.x = 1;
p.y = 2;
// or:
p = CGPointMake(1, 2);
s.width = 3;
s.height = 4;
// or:
s = CGSizeMake(3, 4);
r.origin.x = 1;
r.origin.y = 2;
r.size.width = 3;
r.size.height = 4;
// or:
r.origin = p;
r.size = s;
// or:
r = CGRectMake(1, 2, 3, 4);

Box Blur CGImageRef

I'm attempting to implement a simple Box Blur, but am having issues. Namely, instead of blurring the images it seems to be converting each pixel to either: Red, Green, Blue or Black. Not sure exactly what is going on. Any help would be appreciated.
Please note, this code is simply a first pass to get it working, I'm not worried about speed... yet.
- (CGImageRef)blur:(CGImageRef)base radius:(int)radius {
CGContextRef ctx;
CGImageRef imageRef = base;
NSUInteger width = CGImageGetWidth(imageRef);
NSUInteger height = CGImageGetHeight(imageRef);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
unsigned char *rawData = malloc(height * width *4);
NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(rawData, width, height,
bitsPerComponent, bytesPerRow, colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGContextRelease(context);
char red = 0;
char green = 0;
char blue = 0;
for (int widthIndex = radius; widthIndex < width - radius; widthIndex++) {
for (int heightIndex = radius; heightIndex < height - radius; heightIndex++) {
red = 0;
green = 0;
blue = 0;
for (int radiusY = -radius; radiusY <= radius; ++radiusY) {
for (int radiusX = -radius; radiusX <= radius; ++radiusX) {
int xIndex = widthIndex + radiusX;
int yIndex = heightIndex + radiusY;
int index = ((yIndex * width) + xIndex) * 4;
red += rawData[index];
green += rawData[index + 1];
blue += rawData[index + 2];
}
}
int currentIndex = ((heightIndex * width) + widthIndex) * 4;
int divisor = (radius * 2) + 1;
divisor *= divisor;
int finalRed = red / divisor;
int finalGreen = green / divisor;
int finalBlue = blue / divisor;
rawData[currentIndex] = (char)finalRed;
rawData[currentIndex + 1] = (char)finalGreen;
rawData[currentIndex + 2] = (char)finalBlue;
}
}
ctx = CGBitmapContextCreate(rawData,
CGImageGetWidth( imageRef ),
CGImageGetHeight( imageRef ),
8,
CGImageGetBytesPerRow( imageRef ),
CGImageGetColorSpace( imageRef ),
kCGImageAlphaPremultipliedLast );
imageRef = CGBitmapContextCreateImage (ctx);
CGContextRelease(ctx);
free(rawData);
[(id)imageRef autorelease];
return imageRef;
}
The char colors should be declared as int.
int red = 0;
int green = 0;
int blue = 0;
I just have a comment. I used this script and it really works well and fast. the only thing is that it leaves the frame with width of radius which is not blurred. So I have modified it a bit so that it blurs whole area using mirroring technique near the edges.
For this one needs to put the following lines:
// Mirroring the part between edge and blur raduis
if (xIndex<0) xIndex=-xIndex-1; else if (xIndex>width-1) xIndex=2*width-xIndex-1;
if (yIndex<0) yIndex=-yIndex-1; else if (yIndex>height-1) yIndex=2*height-yIndex-1;
after these lines:
int xIndex = widthIndex + radiusX;
int yIndex = heightIndex + radiusY;
And then replace the headers of for loops:
for (int widthIndex = radius; widthIndex < width - radius; widthIndex++) {
for (int heightIndex = radius; heightIndex < height - radius; heightIndex++) {
with these headers:
for (int widthIndex = 0; widthIndex < width; widthIndex++) {
for (int heightIndex = 0; heightIndex < height; heightIndex++) {