Drawing text with an MKOverlayRenderer - ios

I'm trying to render text on a map using an MKOverlayRenderer. I have an existing, functional MKOverlayRenderer rendering a set of points, so my only problem is rendering a piece of text for each point within the '-(void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context' function.
All solutions I have found through SO and Google use annotations or UILabels. But I want to have the text drawing code in the same location as the code rendering the points. Also there are about 10,000 points, though I'm ensuring it's not rendering them all at the same time through zoom and bounds checking. I am reasonably sure I don't want to create 10,000 objects with the other solutions.
This is the current test code I have to try to render one of the 'Text Text' items. It is a combination of some of the methods I have found on the net to try to render something.
CGPoint* point = self.pointList.pointArray + pointIndex;
CGContextSetRGBFillColor(context, 1.0, 0.0, 0.0, 1.0);
CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);
CGContextSelectFont(context, "Helvetica", 20.f, kCGEncodingFontSpecific);
CGContextSetTextDrawingMode(context, kCGTextFill);
CGAffineTransform xform = CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0.0, 0.0);
CGContextSetTextMatrix(context, xform);
CGContextShowTextAtPoint(context, point->x, point->y, "Test Text 1", 11);
CGContextShowTextAtPoint(context, 10, 10, "Test Text 2", 11);
CGContextShowText(context, "Test Text 4", 11);
UIFont* font = [UIFont fontWithName:#"Helvetica" size:12.0];
[#"Test Text 3" drawAtPoint:*point withFont:font];
This is my first SO questions, so sorry if it isn't that correct.
Edit: I just saw the text when zoomed in as far as I can go, so realise I haven't been accounting for the zoom scale. Assuming I need to do a scale transform before rendering to account for it. Haven't solved it currently, but I think I am on my way.

I have solved it. Sorry for posting this, but I was at my wit's end and thought I needed help.
The line that rendered was:
CGContextShowTextAtPoint(context, point->x, point->y, "Test Text 1", 11);
Which is a deprecated function, but I don't know any other way to render to a specific context.
To fix it, the affine transform became:
CGAffineTransform xform = CGAffineTransformMake(1.0 / zoomScale, 0.0, 0.0, -1.0 / zoomScale, 0.0, 0.0);
The other error was that the 'select font' call needed to become:
CGContextSelectFont(context, "Helvetica", 12.f, kCGEncodingMacRoman);
I had copied the other encoding from some example code I had seen on the net, but it causes the text to have wrong characters.
If there is still a way I can do it without using the deprecated CGContextShowTextAtPoint function I would still love to know.

Related

About contentsTransform. How 3D Transform matrix work?

I heard that I can use contentsTranform modify the texture. But how? the contentsTranform is a SCNMatrix, from the doc I can use SCNMatrix4MakeTranslation、SCNMatrix4MakeRotation and SCNMatrix4MakeScale functions to create a Matrix. But I don't know how to display the texture like the second picture. the photoFrame is a 1:2 and the texture is 1:1.
Twice Edit:
I change the scale and offset and WrapT property in the material editor. And the effect is good. But when I run it, I couldn't get the same effect. So I try to program by change the contentsTransform property. But the scale, offset they both affect the contentsTransform. So if the offSet is (0, -4.03) and the Scale is (1, 1.714), what is the contentsTransform?
Solution moved from #HaoDong's question post.
Now I know what's solution.
First
Don't load .dae file as the SCNScene. You are supported to use .scn file. The error happened because I use .dae file to modify texture in Scene Editor. Then I couldn't get the same result when I run it. After I changed it to .scn file and modify the texture. I get the right effect on real Device. You can simply convert .dae to .scn file by ->Editor->Convert to SceneKit scene file format.
Second
Both offset and Scale value affect the value of contentsTransform property. I have modify the texture in the material Editor View. if the offSet is (0, -4.03) and the Scale is (1, 1.714) the contentsTransform property is SCNMatrix4(m11: 1.0, m12: 0.0, m13: 0.0, m14: 0.0, m21: 0.0, m22: 1.714, m23: 0.0, m24: 0.0, m31: 0.0, m32: 0.0, m33: 1.0, m34: 0.0, m41: 0.0, m42: -4.03, m43: 0.0, m44: 1.0). By searching the doc, I found that how to get this property.
var matrixA = SCNMatrix4MakeTranslation(0, -4.0, 0)
var matrixB = SCNMatrix4MakeScale(1, 1.345, 1)
var b = SCNMatrix4Mult(matrixB, matrixA)
Make sure it is MakeScale * MakeTranslation

iOS the quality of drawing lines using CGContext is much worse than SKShapeNode in SpriteKit

I'm making a game where the user can draw lines with finger. There are tons of methods on websites. I tried two methods, one using CGContext in UIView (UIKit), and the other using CGPath and SKShapeNode in SpriteKit. But the latter shows much better quality. The first one using CGContext has ugly rough edges.
Please see following screen shots. I also attached part of code for both methods here, (in the touchesMove function).
Note: var ref = CGPathCreateMutable()
CGContext in UIView
CGPathAddLineToPoint(ref, nil, currentPoint.x, currentPoint.y)
UIGraphicsBeginImageContext(self.frame.size)
let context = UIGraphicsGetCurrentContext()
tempImageView.image?.drawInRect(CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height))
CGContextAddPath(context, ref)
// 3
CGContextSetLineCap(context, CGLineCap.Round)
CGContextSetLineWidth(context, brushWidth)
CGContextSetRGBStrokeColor(context, red, green, blue, 1.0)
CGContextSetBlendMode(context, CGBlendMode.Normal)
// 4
CGContextStrokePath(context)
// 5
UIGraphicsEndImageContext()
SKShapeNode in SpriteKit
Note: var lineDrawing = SKShapeNode()
CGPathAddLineToPoint(ref, nil, location.x, location.y)
lineDrawing.path = ref
lineDrawing.lineWidth = 3
lineDrawing.strokeColor = UIColor.blackColor()
lineDrawing.alpha = 1.0
self.addChild(lineDrawing)
How can I draw lines in UIView with the same quality of SKShapeNode?
One obvious problem is that you're using an outdated function that doesn't handle Retina screens:
UIGraphicsBeginImageContext(self.frame.size)
You should be using this instead:
UIGraphicsBeginImageContextWithOptions(self.frame.size, false, 0)
The WithOptions version, with 0 as the final argument, creates an image context at Retina resolution if the device has a Retina screen. (The 0 argument means “use the device screen's scale factor”.)
There may be other issues, because you didn't show the code that creates the points in the path for each test case.

How to use CGColorCreate to get white with Swift in iOS

Maybe I'm misinterpreting the information out there but in my code I have:
let color = CGColorCreate(CGColorSpaceCreateDeviceRGB(), [1.0, 1.0, 1.0, 1.0])
Which compiles fine but the text is always black no matter what I set the values to. What should the line look like to get white text?
I think you are missing out the opacity of the colour space. I was able to get a bright, light orange with opacity with this [1.0, 0.5, 0.5, 0.2]. The opacity of the colour is 0.2 in my example.
let colour = CGColorCreate(CGColorSpaceCreateDeviceRGB(), [1.0, 0.5, 0.5, 0.2])
Set the opacity to 1 for a solid colour.
colour? I'm British old boy!
EDIT: Opps, I think I answered to the wrong question.
Did you check your lighting? Try to add the following:
scnView.autoenablesDefaultLighting = true
I was having the same problem when trying to draw text onto an image. I now found out that at least on iOS 8
CGContextSetFillColorWithColor(context, CGColorCreate(CGColorSpaceCreateDeviceRGB(), [1.0, 1.0, 1.0, 1.0]))
doesn't really do anything. To set the color of the text, I rather had to add an attribute to the Dictionary that is in the withFont parameter of
text.drawInRect(rectText, withFont: font)
Example:
Assuming we already have an UIImage image
let font = UIFont(name: "Helvetica", size: 18)
let text: NSString = "String to draw"
let rect = CGRectMake(0, 0, image.size.width, image.size.height)
UIGraphicsBeginImageContextWithOptions(CGSize(width: rect.width, height: rect.height), true, 0)
image.drawInRect(rect)
let attr: NSDictionary = [NSFontAttributeName : font!, NSForegroundColorAttributeName : UIColor.whiteColor() ]
let size = text.sizeWithAttributes(attr)
let rectText = CGRectMake(image.size.width-size.width, image.size.height-(size.height+4), image.size.width-(size.width+4), image.size.height)
text.drawInRect(rectText, withAttributes: attr)
let newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
This example borrows heavily from the blog post at http://www.bytearray.org/?p=5416.

How to display dashed lines in objective-c?

I have this code to display a grid with dashed line. In runtime on an iphone 5 below it shows fine, but if I run the app on iphone 5s there's no grid. I tested in iPhone Simulator and on real devices and happens the same.
Here's the code:
if (self.dashLongitude) {
CGFloat lengths[] = {3.0, 3.0};
CGContextSetLineDash(context, 0.0, lengths, 2);
}
//other stuff here
CGContextSetLineDash(context, 0, nil, 0);
So anyone could help??
EDIT: Hey guys I solved the issue using the same code I posted here, but in a different method. So I have now two methods: one just for the drawing the grid and another on to draw the line with data and finally got everything working.
The code looks fine.
As I look into the code I saw you are setting the nil in the context. nil is used to remove the dashed line.
Try to use
CGFloat dash[] = {2.0, 2.0};
CGContextSetLineDash(context, 0.0, dash, 2);
where you are creating or provide stroke your line(underneath).
CGContextSetLineDash(context, 0, NULL, 0);
is used to remove that dash pattern.
Instead of setting nil in CGContextSetLineDash, just wrap your code into CGContextSaveGState/CGContextRestoreGState to preserve context state before applying line dash:
CGContextSaveGState(context);
CGFloat dash[] = {2.0, 2.0};
CGContextSetLineDash(context, 0.0, dash, 2);
// Draw some lines here
CGContextRestoreGState(context);

Showing text with CGContextShowTextAtPoint draws strange text

I'm just trying to overlay a text in a UIImage (using CGContext) but it doesn't show the text I specified. In this code I'm giving as the text argument "Hello" but it shows "eÉääc". I don't know what's happening I think the characters are displaced but I don't know how to solve it.
This is my code:
UIGraphicsBeginImageContextWithOptions(image.size, YES, 0);
CGContextRef c = UIGraphicsGetCurrentContext();
[image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
CGContextSetTextMatrix(c, CGAffineTransformMake(1.0, 0, 0, -1.0, 0, 0));
CGContextSelectFont(c, "ArialMT", 50, kCGEncodingFontSpecific);
CGContextSetRGBStrokeColor(c, 255, 0, 0, 1);
CGContextSetRGBFillColor(c, 255, 0, 0, 1);
CGContextSetCharacterSpacing(c, 2);
CGContextShowTextAtPoint(c,100,100, "Hello", 5);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
I'm using the Spanish Keyboard (I don't know if this matters) and the iPad (where I'm testing the application) is in Catalan.
CGContextShowTextAtPoint() interprets the given text according to the specified encoding parameter of CGContextSelectFont. You have chosen kCGEncodingFontSpecific, which is the font built-in encoding (whatever that might be).
The only other choice is kCGEncodingMacRoman:
CGContextSelectFont(c, "ArialMT", 50, kCGEncodingMacRoman);
Then your text should display correctly, as long as you use only characters from the ASCII character set.
For non-ASCII characters, you have to convert the string to the MacRoman encoding, see e.g. https://stackoverflow.com/a/13743834/1187415 for an example.
Note that CGContextShowTextAtPoint cannot display general Unicode strings, and even has problems with the Euro (€) character. The drawAtPoint:withFont: method of NSString does not have these limitations.

Resources