How to display Text on a PieChart? - iphone

I have Created a PieChart Using the following Code. Here, I Have taken the sum of x and y as 100% to display the x% as red color and y% as green color on pieChart.
On the red color i want to display the exact x% (Example 45% (or) 55%) and on the green color i want to display the exact y% (Example 55% (or) 45%).
In my application the X and Y values are Variables. Those Values are changing each time when i run my application. I want to display the pieChart with green and red colors with the percentage on those regions. How Can i make frames to display percentages on that regions?
.m file
- (void)drawRect:(CGRect)rect
{
// Drawing code
int x = 25;
int y = 42;
float sum = x + y;
float mult = (360/sum);
float startDeg = 0;
float endDeg = 0;
int x = 74;
int y = 60;
int r = 60;
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(ctx, 1.0, 1.0, 1.0, 1.0);
CGContextSetLineWidth(ctx, 2.0);
startDeg = 0;
endDeg = (x * mult);
if(startDeg != endDeg)
{
CGContextSetRGBFillColor(ctx, 0.0, 0.8, 0.0, 1.0);
CGContextMoveToPoint(ctx, x, y);
CGContextAddArc(ctx, x, y, r, (startDeg)*M_PI/180.0, (endDeg)*M_PI/180.0, 0);
CGContextClosePath(ctx);
CGContextFillPath(ctx);
}
startDeg = endDeg;
endDeg = endDeg + (y * mult);
if(startDeg != endDeg)
{
CGContextSetRGBFillColor(ctx, 0.8, 0.0, 0.0, 1.0);
CGContextMoveToPoint(ctx, x, y);
CGContextAddArc(ctx, x, y, r, (startDeg)*M_PI/180.0, (endDeg)*M_PI/180.0, 0);
CGContextClosePath(ctx);
CGContextFillPath(ctx);
}
}

You can draw a string with NSString drawInRect during the drawRect method. For example:
[percentageString drawInRect:CGRectMake(100, 100, 30, 20)
withFont:font
lineBreakMode:UILineBreakModeClip
alignment:UITextAlignmentLeft];
Update
Here is how to find the x, y for placing text:
CGFloat startDegree = 180; // start at 180
CGFloat endDegree = degree; // end at some value
CGFloat mid = (endDegree + startDegree) / 2; // find midpoint
CGFloat rad = DEGREES_TO_RADIANS(mid); // convert to radians
// center is center of pie chart
// radius is how big the pie chart is
// 30 is extra to draw text outside circle
CGFloat x = center.x + ((radius + 30) * cos(rad));
CGFloat y = center.y + ((radius + 30) * sin(rad));
NSLog(#"X Y: %f %f %f", x, y, degree);
NSString *text = #"Test";
[text drawInRect:CGRectMake(x, y, 50, 44) withFont:[UIFont systemFontOfSize:14.0f]];
I had a sample pie chart so I used that. It has a slider with degrees. In the example, I can draw a segment of the pie chart from 180 degrees to 360 degrees.

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

Drawing a ruler in objective c 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);

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?

UIControl for a Needle Gauge aka Google O Meter

For those times when a UISlider just isn't fun enough I was thinking I'd work up a custom UIControl to do something similar to a Google O Meter from the google chart API on iOS.
Here's an example of what I'm talking about visually. My goal would be to enable touch manipulation of the needle and easy customization of the range labels and coloring gradients. The Google Charts API is a great inspiration:
Before I re-invent the wheel is anyone aware of an existing effort I could leverage good sample code with something like this or project I could contribute too?
Thanks for any pointers.
I have implemented a GaugeView as a child of UIView and added the code to draw the gauge in the drawRect method. Nothing fancy but may be helpful to start
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
CGRect parentViewBounds = self.bounds;
CGFloat x = CGRectGetWidth(parentViewBounds)/2;
CGFloat y = CGRectGetHeight(parentViewBounds);
CGFloat radius = y;
CGFloat percent_angle = _progress * M_PI;
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextBeginPath(ctx);
// Add path
CGFloat m2_x = radius * (1.0 - 0.9*cos(percent_angle));
CGFloat m2_y = radius * (1.0 - 0.9*sin(percent_angle));
CGContextBeginPath(ctx);
CGContextAddArc(ctx, x, y, radius, M_PI, 0, 0);
CGContextAddLineToPoint(ctx, x + 0.1*radius, y);
CGContextAddArc(ctx, x, y, 0.1*radius, 0, M_PI, 1);
CGContextClosePath(ctx);
CGContextSetFillColorWithColor(ctx,[UIColor whiteColor].CGColor);
CGContextFillPath(ctx);
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, m2_x, m2_y);
CGContextAddArc(ctx, x, y, 0.9*radius, M_PI + percent_angle, M_PI, 1);
CGContextAddLineToPoint(ctx, 0.8*radius, y);
CGContextSetStrokeColorWithColor(ctx,self.fillColor.CGColor);
CGContextAddArc(ctx, x, y, 0.2*radius, M_PI, M_PI + percent_angle, 0);
CGContextClosePath(ctx);
CGContextStrokePath(ctx);
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, m2_x, m2_y);
CGContextSetFillColorWithColor(ctx,self.fillColor.CGColor);
CGContextAddArc(ctx, x, y, 0.9*radius, M_PI + percent_angle, M_PI, 1);
CGContextAddLineToPoint(ctx, 0.8*radius, y);
CGContextAddArc(ctx, x, y, 0.2*radius, M_PI, M_PI + percent_angle, 0);
CGContextClosePath(ctx);
CGContextFillPath(ctx);
/* CGContextBeginPath(ctx);
CGContextAddArc(ctx, x, y, radius, M_PI, 0, 0);
CGContextAddLineToPoint(ctx, x + 0.1*radius, y);
CGContextAddArc(ctx, x, y, 0.1*radius, 0, M_PI, 1);
CGContextClosePath(ctx);
CGContextSetStrokeColorWithColor(ctx,[self.strokeColor CGColor]);
CGContextStrokePath(ctx);*/
for(int i = 0; i < 100; i++)
{
CGFloat angle =M_PI * 0.01 * i;
CGFloat l1_x = radius * (1.0 - 0.98*cos(angle));
CGFloat l1_y = radius * (1.0 - 0.98*sin(angle));
if(i%10 == 0)
{
l1_x = radius * (1.0 - 0.9*cos(angle));
l1_y = radius * (1.0 - 0.9*sin(angle));
}
else if(i%5 == 0)
{
l1_x = radius * (1.0 - 0.95*cos(angle));
l1_y = radius * (1.0 - 0.95*sin(angle));
}
CGFloat l2_x = radius * (1.0 - cos(angle));
CGFloat l2_y = radius * (1.0 - sin(angle));
CGContextMoveToPoint(ctx, l1_x, l1_y);
CGContextSetLineWidth(ctx, 1.0);
CGContextAddLineToPoint(ctx, l2_x, l2_y);
CGContextSetStrokeColorWithColor(ctx,[self.strokeColor CGColor]);
CGContextStrokePath(ctx);
}
CGFloat n1_x = radius * (1.0 - 0.1*cos(percent_angle));
CGFloat n1_y = radius * (1.0 - 0.1*sin(percent_angle));
CGFloat n2_x = radius * (1.0 - cos(percent_angle));
CGFloat n2_y = radius * (1.0 - sin(percent_angle));
CGContextMoveToPoint(ctx, n1_x, n1_y);
CGContextSetLineWidth(ctx, 4.0);
CGContextAddLineToPoint(ctx, n2_x, n2_y);
CGContextSetStrokeColorWithColor(ctx,[self.needleColor CGColor]);
CGContextStrokePath(ctx);
}

rotating a circle in UIView?

I want to draw a circle in drawRect through a context like a pie chart thorugh UITouch (took from a tutorial)? I have given the code as follows, how can I rotate? Any help please?
#define PI 3.14159265358979323846
#define snapshot_start 360
#define snapshot_finish 360
static inline float radians(double degrees) { return degrees * PI / 180; }
- (void)drawRect:(CGRect)rect
{
// Drawing code
CGRect parentViewBounds = self.bounds;
CGFloat x = CGRectGetWidth(parentViewBounds)/2;
CGFloat y = CGRectGetHeight(parentViewBounds)*0.55;
// Get the graphics context and clear it
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextClearRect(ctx, rect);
// define stroke color
CGContextSetRGBStrokeColor(ctx, 1, 1, 1, 1.0);
// define line width
CGContextSetLineWidth(ctx, 4.0);
// need some values to draw pie charts
double snapshotCapacity =20;
double rawCapacity = 100;
double systemCapacity = 1;
int offset = 5;
double pie1_start = 315.0;
double pie1_finish = snapshotCapacity *360.0/rawCapacity;
double system_finish = systemCapacity*360.0/rawCapacity;
CGContextSetFillColor(ctx, CGColorGetComponents( [[UIColor greenColor] CGColor]));
CGContextMoveToPoint(ctx, x+2*offset, y);
CGContextAddArc(ctx, x+2*offset, y, 100, radians(snapshot_start), radians(snapshot_start+snapshot_finish), 0);
CGContextClosePath(ctx);
CGContextFillPath(ctx);
// system capacity
CGContextSetFillColor(ctx, CGColorGetComponents( [[UIColor colorWithRed:15 green:165/255 blue:0 alpha:1 ] CGColor]));
CGContextMoveToPoint(ctx, x+offset,y);
CGContextAddArc(ctx, x+offset, y, 100, radians(snapshot_start+snapshot_finish+offset), radians(snapshot_start+snapshot_finish+system_finish), 0);
CGContextClosePath(ctx);
CGContextFillPath(ctx);
/* data capacity */
CGContextSetFillColor(ctx, CGColorGetComponents( [[UIColor colorWithRed:99/255 green:184/255 blue:255/255 alpha:1 ] CGColor]));
CGContextMoveToPoint(ctx, x, y);
CGContextAddArc(ctx, x, y, 100, radians(snapshot_start+snapshot_finish+system_finish+offset), radians(snapshot_start), 0);
CGContextClosePath(ctx);
CGContextFillPath(ctx);
}