How would I smooth a line (UIBeizerPath) or a set of points? Right now it draws it jagged. I read about spline interpolation, could anyone point me to an implementation of this in cocoa or C or give me an alternate line smoothing algorithm.
I don't think you need to do Bezier paths with curves. You can keep drawing straight line segments but add more data points with interpolation. This is especially important because I'm assuming you want to smooth only on one axis so you don't end up with odd things like loops in your graph.
So you want to add more points to your source data, between the existing points, and use an interpolation algorithm that's more sophisticated than a linear interpolation. There are many to choose from. Quadratic? Sine-based? Many, and it depends on what kind of data you're using.
Quartz (which UIKit uses for drawing, and in many places makes you use directly for drawing) has anti-aliasing support built-in. Most contexts have it turned on already, so you should not have aliased (jagged) drawing unless you're turning anti-aliasing off. So, stop doing that. :-)
The contexts that don't have it turned on by default are mostly those where it isn't appropriate, such as PDF contexts and CGLayer contexts. The documentation implies that those contexts don't even support anti-aliasing, which makes some amount of sense.
CGContext provides a couple of functions for turning anti-aliasing on and off, but you should never need to call them except when you want aliasing, which you don't. You could try turning it on using those functions; if that works, then you should investigate why it was ever off in the first place.
Are you drawing the path from within a CALayer? That may be why it's off; there's an Info.plist key you have to turn on to get anti-aliasing turned on by default in such contexts.
I've found that if you draw a line or an image on the edge of your frame that it will appear jagged. Move the line in a few (or grow your frame) and it should appear nice and crisp. Again, not sure if that's your question or not but it has bit me a few times.
For instance if you are displaying an image inside a CALayer, make sure there is space between the image and the frame if you are doing anything but 90 degree angles.
Related
I'm creating a puzzle game that generates random sized pieces with 2D meshes. The images contain transparent portions and sometimes a piece is completely transparent. I need to detect what percentage of a piece is transparent. One way I found to do this is to go pixel by pixel. I posted my solution to this HERE. However, this process adds a few seconds during loading which I'd like to avoid and I'm looking for other ideas
I've considered using the selection outline of a MeshCollider to somehow to get a surface area I can compare to the surface area of the mesh but everything I find is on the rendering of outline with specialized shaders. Does anyone have any ideas on to solve this?
.
1) I guess you could add a PolygonCollider2D to your sprite and use its Path for the outline and calculation of the surface area. Not sure however if this will be faster.
PolygonCollider2D.GetPath:
A path is a cyclic sequence of line segments between points that define the outline of the Collider
Checking PolygonCollider2D.GetTotalPointCount or path length may be good enough to determine if the sprite is 'empty'.
Sprite.vertices, Sprite.triangles may also be helpful.
2) You could also improve performance of your first approach:
instead of calling GetPixel as you do now use GetPixels or GetPixels32 and loop through the array in one for loop.
Using GetPixels can be faster than calling GetPixel repeatedly, especially for large textures. In addition, GetPixels can access individual mipmap levels. For most textures, even faster is to use GetPixels32 which returns low precision color data without costly integer-to-float conversions.
check only every 2nd or nth pixel as it should be good enough for approximation
limit number of type casts
I have made an application which draws a number of curves, using UIBezierPath. Now I'm trying to implement a modification functionality in it. To modify the particular curve one thing I can do is to draw all the curves again; I have not yet implemented this. But I think this algorithm would not be very efficient when the number of curves increases because I have to store all the points in the array and I have to run for loop to draw each curve every time I go for modification.
I am looking for more efficient algorithm. It will be helpful if someone can provide example code.
You can represent individual curves as UIBezierPaths and draw them separately by creating one CAShapeLayer per curve and assigning the shape layer's path property to the corresponding CGPath property of the bezier path. To update an individual curve, you then just have to manipulate one bezier path and the corresponding shape layers path property.
Redraw the curve until you have a performance problem as measured with Instruments. If that occurs again use Instruments to pinpoint the best way to optimize.
It is easy to get sucked into spending time on optimizations that are never needed. Initially it is much better to put that time and thinking into creating a "clean" code.
I have the layout of a website in CorelDraw X4 and I need to move it to Fireworks CS5 (for many reasons). The thing is that, apparently, the only method I was able to find on the Internet doesn't work very well. What I do is to export the file from Draw to AI (Adobe Illustrator) format. Then I import the file in fireworks, but there, strange things happen. The first thing is that borders are thicker after this process (1 to 4) but the real problem comes with some objects thar are converted to bitmaps (or so I think). When I delete all the bitmaps, only a few objects remain and that's obviously undesired. In my original file I use transparencies and gradients applied to many different objects.
Do you know why this happens and/or a possible solution? Thanks!
Edit: I think I'm getting closer! Apparently AI format doesn't support transparencies, so... I get all trasparencies out before exporting (not very nice, but what can I do, right?) or I ungroup all objects once imported into Fireworks and then carefully delete the bitmaps (which seem to be the approximation of transparencies for AI). All this is just about testing, if someone knows what happens or of another solutions, please, thow light. Thanks...
Ok, as nobody else answered my question I suppose I can consider myself capable to provide more information than anybody else, ha!
I've been studing the case and reached to a semi-solution. Apparently, AI is the only format supporting vectors that can be exported and imported by both editors. The problem with this is that AI doesn't support transparencies nor shadows. So... If you really want to do this, be prepared to work a bit.
What I did was to copy all the shapes without effects using this export/import method (surprisingly, line thickness was preserved correctly this time), then I examined shape by shape in Corel and applied the same (or its best aproximation) effects in Fireworks. This wasn't easy because the way both programs apply shadows and transparencies is a bit different. Yeah, it's not easy, but it's all we got...
Little tip: In my case I had some shapes with transparencies AND shadows. In Corel these shadows where strong as if the object was solid (not transparent). In fireworks, the shadow disappears with the object when the transparency is applied (as logically expected). What I did to solve this was to copy the object and apply a Gaussian blur to the object in the back, acting as a full shadow even when the object in the front was fading to transparent.
When I'm using a UIBezierPath to draw where the user is touching if the user moves to fast sometimes I get really hard points like the tip of a triangle. Any clue what might be causing this? Or how I can fix it?
I am capturing the points using touchesBegan/Moved/Ended and placing them into an NSArray of UIBezierPaths.
Despite the name, UIBezierPath doesn't just draw curves. In fact, by default it won't - presumably you're simply passing the coordinates returned by touchesBegan etc, into the addLineToPoint method.
Instead of simply passing all the touch coordinates directly into a UIBezierPath you should first interpolate them to avoid these sharp lines that occur when you rapidly move your finger across the screen. This is not too difficult, although does require some knowledge of how bezier curves work and spline interpolation.
If you are looking for a slightly easier way out, there are a couple of open source libraries that will do this for you, like this one: http://cocoacontrols.com/platforms/ios/controls/smooth-line-view
My Question is something similar to this.
I have 2 CGPathRef and 1 will be moved by finger touch. I want to find that whether the 2 CGPathRef are intersected? That question was asked almost 2 years ago and I want to know whether something has been found in the mean time.
This is fairly old, but I found it looking for a similar solution, in my problem I wanted to find when a circle overlapped with a path (a special case of your question).
I solved this by using CGPathCreateCopyByStrokingPath to create a stroked version of the original path using the radius of the circle as the stroke width. If the center point of the circle overlaps the stroked path then the original path overlaps the circle.
BOOL CGPathIntersectsCircle(CGPathRef path, CGPoint center, CGFloat radius)
{
CGPathRef fuzzyPath;
fuzzyPath = CGPathCreateCopyByStrokingPath(path, NULL, radius,
kCGLineCapRound,
kCGLineJoinRound, 0.0);
if (CGPathContainsPoint(fuzzyPath, NULL, center, NO))
{
CGPathRelease(fuzzyPath);
return YES;
}
CGPathRelease(fuzzyPath);
return NO;
}
Edit: A minor bug where the fuzzyPath was not released.
I have written a small pixel based path collision detection API for CGPathRefs. It requires that you add a few source directories to your project, and it only works with ARC, but it should at least show you how one might do something like this. It basically draws the two paths on two separate contexts, and then does pixel-by-pixel checks to see if any pixels are on both paths. Obviously this would be slow to run every time the user drags their finger, but it certainly could be done once every half second or so, maybe not even on the main thread.
This is the easiest way I've found of doing something like this, and it may easily be that there's no better way, besides using lots of math.
The source on Github
A quick Youtube demo.
Generally speaking, finding the intersection of two arbitrary CGPaths is going to be very complex.
There are ways to do approximations. Checking the intersections of the bounding boxes is a good first step. You can also subdivide the curve and repeat the process to get better approximations. Another option is to flatten the paths and see if any of the line segments of the flattened paths intersect.
For the general case, however, things get very nasty very fast. Consider, for example, the fact that two cubic bezier segments (never mind an entire path... just one segment) can intersect with another segment at up to 6 points. The more segments in your path, the more potential intersections. There is also the problem of degenerate bezier curves where a segment has a cusp that just touches one point of another segment. Does that count as an intersection? (sometimes yes, sometimes no)
It's not clear from your question, but you might also want to consider the intersections of the strokes that are applied to the curves, and correctly account for line joins and miters. That that gets even harder. Macromedia FreeHand (a drawing program similar to Adobe Illustrator) had a very large, complex, intensely mathematical library for discovering arbitrary bezier curve intersections. The problem is not easily solved.
To find the intersection of two CAShapeLayers, we can use below method, CAShapeLayer won't return frame. But we can get the refPath frame using CGPathGetBoundingBox. But this one will give the frame in rectangle.I thing you may understand.
if (CGRectIntersectsRect(CGPathGetBoundingBox(layer.path), CGPathGetBoundingBox(layer.path)))