I want to draw text use Quartz 2D. The "menu" direction is wrong. I want "Menu" still readable and have 45 degree with X-axis. Below is my code:
CGContextSelectFont(context, "Arial", 12, kCGEncodingMacRoman);
CGContextSetTextDrawingMode(context, kCGTextFill);
CGContextSetRGBFillColor(context, 0, 0, 0, 1); // 6
CGContextSetRGBStrokeColor(context, 0, 0, 0, 1);
CGContextSetTextMatrix(context, CGAffineTransformMake(1.0,0.0, 0.0, -1.0, 0.0, 0.0));
CGContextSetTextMatrix(context, CGAffineTransformMakeRotation(45));
CGContextShowTextAtPoint(context,10, 10, "Menu", 4);
CGAffineTransformMakeRotation expects angle in radians, not in degrees.
#define DEGREES_TO_RADIANS(x) (M_PI * (x) / 180.0)
...
CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(45));
[view setTransform:CGAffineTransformMakeRotation(M_PI / 2)];
Related
EDIT:
What I am trying to achieve is skip the call to firstDraw() the second time that drawRect is called. Reason for this is that in my real code I have got a lot of data points and lines to draw, so I thought thata if I recycle the previously drawn things I could optimize the performance. Is this possible at all with CoreGraphics?
I'd like to be able to perform multiple drawings on a UIView without having to re-draw what I have already drawn.
The code below will execute two draws at a time distance of 2.4 seconds. After the first call I use CGContextSaveGState to save the state. In the second call I retrieve the current graphic context and then add some lines. However this seem to fail as it appears that the previous context is lost.
What I get:
Here is what I get at the first draw call:
Here is what I get after the second call:
This instead is what I would like to get instead after the second call:
Here is the code:
import UIKit
class GraphView: UIView {
var count : Int = 0
override func drawRect(rect: CGRect) {
if ( count == 0){
firstDraw()
NSTimer.scheduledTimerWithTimeInterval(2.4, target: self, selector: "setNeedsDisplay", userInfo: nil, repeats: false)
count++
}
else{
addLinesToDraw()
}
}
func firstDraw(){
// Drawing code
let context = UIGraphicsGetCurrentContext()
CGContextMoveToPoint(context, 50, 50);
CGContextSetRGBStrokeColor(context, 0, 0, 0, 1.0);
CGContextSetRGBFillColor(context, 0, 0.0, 0.0, 1.0);
CGContextAddLineToPoint(context, 60, 60);
CGContextMoveToPoint(context, 150, 150);
CGContextAddLineToPoint(context, 110, 90);
CGContextSetLineWidth(context, 2);
CGContextStrokePath(context);
// Draw a Point as a small square
CGContextSetRGBStrokeColor(context, 0.5, 0.5, 0.5, 1.0);
CGContextSetRGBFillColor(context, 0.5, 0.5, 0.5, 1.0);
//NSLog(#"Drawing rect at point [x: %i, y: %i]", xPosition+resolution, pressureIntValue);
CGContextFillRect(context, CGRectMake(0, 0, 10, 10));
CGContextAddRect(context, CGRectMake(0, 0, 10, 10));
CGContextStrokePath(context);
CGContextSaveGState(context)
}
func addLinesToDraw(){
// Drawing code
let context = UIGraphicsGetCurrentContext()
CGContextMoveToPoint(context, 30, 60);
CGContextSetRGBStrokeColor(context, 0, 0, 0, 1.0);
CGContextSetRGBFillColor(context, 0, 0.0, 0.0, 1.0);
CGContextAddLineToPoint(context, 20, 20);
CGContextMoveToPoint(context, 120, 250);
CGContextAddLineToPoint(context, 110, 90);
CGContextSetLineWidth(context, 2);
CGContextStrokePath(context);
// Draw a Point as a small square
CGContextSetRGBStrokeColor(context, 0.5, 0.5, 0.5, 1.0);
CGContextSetRGBFillColor(context, 0.5, 0.5, 0.5, 1.0);
//NSLog(#"Drawing rect at point [x: %i, y: %i]", xPosition+resolution, pressureIntValue);
CGContextFillRect(context, CGRectMake(20, 30, 10, 10));
CGContextAddRect(context, CGRectMake(20, 30, 10, 10));
CGContextStrokePath(context);
CGContextSaveGState(context)
}
}
Each time you call drawRect:, you have to draw everything from scratch. So, in your case, you want to change your code to something like:
override func drawRect(rect: CGRect) {
firstDraw()
if ( count == 0){
NSTimer.scheduledTimerWithTimeInterval(2.4, target: self, selector: "setNeedsDisplay", userInfo: nil, repeats: false)
count++
}
else{
addLinesToDraw()
}
}
If you don't like this solution, you could always do all your drawing in a separate CGContext and blit it to the screen in your drawRect method.
Use UIGraphicsPushContext(context) instead of CGContextSaveGState(context) to make your context the current drawing context.
Difference described here: CGContextSaveGState vs UIGraphicsPushContext
I am trying out a simple fill, two intersecting circles with same radius and to fill the intersection alone.Below is what I tried
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 1.0);
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextSetStrokeColorWithColor(context, [UIColor yellowColor].CGColor);
// Draw first circle
CGContextAddArc(context, 150, 150, 50, 0, 2 * M_PI, 1);
CGContextStrokePath(context);
// Draw second circle
CGContextAddArc(context, 200, 150, 50, 0, 2 * M_PI, 1);
CGContextEOClip(context);
CGContextFillPath(context);
}
My code doesn't even render second circle in context. I have gone through lot of question related to CGContextClip here in forum but most of them uses CGPath in their sample. Only CGpaths can be clipped? Any suggestions or ideas are appreciated.
Thank you
The functions CGContextStrokePath(), CGContextEOClip() and CGContextFillPath()
all clear the current path. Therefore the final CGContextFillPath() has no path to fill.
The following code should now work to draw the intersection of the circles:
// Use first circle as clipping path:
CGContextAddArc(context, 150, 150, 50, 0, 2 * M_PI, 1);
CGContextClip(context);
// Draw second circle:
CGContextAddArc(context, 200, 150, 50, 0, 2 * M_PI, 1);
CGContextFillPath(context);
Update: The following code fills and strokes the intersection:
CGContextSaveGState(context);
CGContextAddArc(context, 150, 150, 50, 0, 2 * M_PI, 1);
CGContextClip(context);
CGContextAddArc(context, 200, 150, 50, 0, 2 * M_PI, 1);
CGContextDrawPath(context, kCGPathFillStroke);
CGContextRestoreGState(context);
CGContextAddArc(context, 200, 150, 50, 0, 2 * M_PI, 1);
CGContextClip(context);
CGContextAddArc(context, 150, 150, 50, 0, 2 * M_PI, 1);
CGContextDrawPath(context, kCGPathStroke);
(Original code which does not work:)
To fill and stroke a path, use CGContextDrawPath():
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 1.0);
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextSetStrokeColorWithColor(context, [UIColor yellowColor].CGColor);
CGContextAddArc(context, 150, 150, 50, 0, 2 * M_PI, 1);
CGContextAddArc(context, 200, 150, 50, 0, 2 * M_PI, 1);
CGContextDrawPath(context, kCGPathEOFillStroke);
Did you tried this
- (UIImage *)colorImage:(UIImage *)origImage withColor:(UIColor *)color
{
UIGraphicsBeginImageContextWithOptions(origImage.size, YES, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, (CGRect){ {0,0}, origImage.size} );
CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, origImage.size.height);
CGContextConcatCTM(context, flipVertical);
CGContextDrawImage(context, (CGRect){ pt, origImage.size }, [origImage CGImage]);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
and you can also try Flood Fill
I want to create a CC3MeshNode with boundingvolume in cocos3d. I have created a CC3MeshNode with a pod file. I want to get notification on collision .
-(void) initializeScene
{
[self addContentFromPODFile: #"hello-world.pod" withName:#"pod1"];
CC3MeshNode *object1 = (CC3MeshNode*)[self getNodeNamed: #"pod1"];
CC3MeshNod *object2=[[object1 copyWithName:#"pod1"]autorelease];
[object1 populateAsSolidBox:CC3BoundingBoxMake(9.5, 5.0, 4.0, 0.0, 0.0, 0.0)]; object1.location=cc3v(-5.0, 0.0, 0.0); object2.location=cc3v(5.0, 0.0, 0.0);
[self addChild:object2];
CCActionInterval *move1=[CC3MoveTo actionWithDuration:3.0 moveTo:cc3v(-1.0, 0.0, 0.0)]; CCActionInterval *move2=[CC3MoveTo actionWithDuration:3.0 moveTo:cc3v(1.0, 0.0, 0.0)]; [object1 runAction:move1];
[object2 runAction:move2];
}
-(void) updateAfterTransform: (CC3NodeUpdatingVisitor*) visitor
{
if([object1 doesIntersectNode:object2])
NSLog(#"Collision !!!!!!!!!!!!!!!!!!!!!!");
}
I tried to assign boundingvolume but didnt work. Actually i am confused in implementing boundingvolume for cc3MeshNode
Your comment above says:
I get error in [object1 populateAsSolidBox:CC3BoundingBoxMake(9.5, 5.0, 4.0, 0.0, 0.0, 0.0)];
Here's why you have the error. From the CC3Foundation documentation it looks like you are setting the max values in CC3BoundingboxMake to a value lower than the mins (they are all zero), in the call
CC3BoundingBoxMake(9.5, 5.0, 4.0, 0.0, 0.0, 0.0)];
That is, from the link above, the signature of CC3BoundingBoxMake() is
CC3BoundingBoxMake ( GLfloat minX,
GLfloat minY,
GLfloat minZ,
GLfloat maxX,
GLfloat maxY,
GLfloat maxZ
)
where your minX is 9.5 and your maxX is 0.0, your minY is 5.0 and your maxY is 0.0, and your minZ is 4.0 and your maxZ is 0.0.
I'm writing on an image using:
float shadowColorValues[] = {0, 0, 0, .3};
CGContextSetShadowWithColor(context, CGSizeMake (2, -2), 3 * imageScale, shadowColor);
CGContextSelectFont(context, newFontName, fontSize, kCGEncodingMacRoman);
CGContextSetRGBFillColor(context, 255, 255, 255, 1);
CGContextSetRGBStrokeColor(context, 255, 255, 255, 1);
CGContextSetTextDrawingMode(context, kCGTextFill);
CGContextSetTextMatrix(context, CGAffineTransformMake(1.0, 0.0, 0.0, 1.0, 0.0, 0.0));
CGContextShowTextAtPoint(context, textX, textY, newText, strlen(newText));
If I'm using a font like Chalkduster the result is very pixelated: http://i.imgur.com/WooNB.png. What am I doing wrong?
Make sure to use
void UIGraphicsBeginImageContextWithOptions(
CGSize size,
BOOL opaque,
CGFloat scale // pass 0 for screen scale
);
when creating the image context.
I'm going to write a texture atlas manager, but I've run into a problem. When I modified my original UV coordinates, my program no longer rendered anything?? This is my draw code:
- (void)drawFrame {
[(EAGLView *)self.view setFramebuffer];
//GLfloat aspectRatio = self.view.bounds.size.height/self.view.bounds.size.width;
float m[16] = {2/self.view.bounds.size.width, 0, 0, 0, 0, 2/self.view.bounds.size.height, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1 };
CGSize imageSize = CGSizeMake(512, 512);
CGRect drawBounds = CGRectMake(0, 0, 106, 126);
GLfloat x = (1/imageSize.width) * drawBounds.size.width;
GLfloat y = (1/imageSize.height) * drawBounds.size.height;
static const GLfloat vertices[] = {
-53.0f, -63.0f,
53.0f, -63.0f,
-53.0f, 63.0f,
53.0f, 63.0f,
};
GLfloat texCoords[] = {
0.0, 0.0,
x, 0.0,
0.0, y,
x, y
};
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
[[TextureLibrary sharedTextureLibrary] bindTexture:#"bounce" toSlot:GL_TEXTURE0];
glUniform1f(uniforms[UNIFORM_TEXTURE], 0);
glUniformMatrix4fv(UNIFORM_MVP_MATRIX, 1, GL_FALSE, m);
glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, vertices);
glEnableVertexAttribArray(ATTRIB_VERTEX);
glVertexAttribPointer(ATTRIB_TEXTURE_POSITION, 2, GL_FLOAT, 0, 0, texCoords);
glEnableVertexAttribArray(ATTRIB_TEXTURE_POSITION);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
[(EAGLView *)self.view presentFramebuffer];
}
However, it works fine like this:
GLfloat texCoords[] = {
0.0, 0.0,
1.0, 0.0,
0.0, 1.0,
1.0, 1.0
};
Help?
Just a guess, but OpenGL considers (0, 0) to be the lower left corner of an image. Is it possible your graphic is in the top left, so that the area you're displaying is actually from a transparent part of the texture?
If so then you can either adjust your texture coordinates or adjust the texture matrix stack so that (0, 0) is in the top left.