I need to separate the screen into regions that look like this (separated by black lines):
The documentation says Most regions are rectangular or elliptical in shape, but you can use the methods of this class to create more complex shapes by adding, subtracting, and intersecting other regions. I can't figure out how to create these.
For context I am trying to replicate the StickyCorners: Using UIFieldBehavior and other UIDynamicBehaviors demo, but adding 4 more sticky points, 1 at each midpoint (indicated by red circles).
Related
This is not asking the same question as How can I combine UIBezierPath drawings? even though the name is similar
I have a shape that needs to be able to scale vertically and on one side of it are rounded corners and the other side is some other path. I have drawn the following image to show what I am talking about, but this is not the exact shape I am making, but conceptually it is the same idea.
In this image, the left side is half of a rounded rectangle and the right side is half of a circle.
So I am wanting to take and essentially cut a rounded rectangle in half and basically "merge" it with another path. How can I do this?
I guess one way would be to have two layers: the top layer contains the shape on the right and the bottom layer contains the rounded rectangle, and the top layer occludes half of the rectangle. But I was hoping to not have to use two different layers, and instead be able to put all of this in one layer, so I was wondering if it was possible to merge the shapes like I mentioned.
Me and my team are working on an app for a client. We are trying to understand how to achieve this kind of animations (refer only to the circle stroke) :
We tried using a CADisplayLink to set up and change the circle, but it generated non-fluid results.
We couldn't find a way to create a circle from "components" of UIBezierPath and change each of the anchors.
Any suggestions on how to achieve this kind of effect, or how to construct a circle from seperated points, would be highly appricated
Best Regards,
Roi and the team
I suggest using Catmull-Rom splines. Those allow you to create smooth curves using only points that are on the curve, whereas Bezier curves require that you define control points that are not on the curve.
Once you have beginning and ending CGPaths its pretty easy to create a CAAnimation of the path from it's starting to it's ending state (although animating change to a CGPath only works correctly if the starting and ending paths in the animation have the same number and type of points.)
You could probably also use Bezier curves, but you would need to generate the control points for the circle and it's distorted shape.
Check out this sample app that uses Catmull-Rom splines to create a distorted circle shape:
http://wareto.com/animating-shapes-using-cashapelayer-and-cabasicanimation
(Written in Objective-C, but the technique is the same in Swift.)
A Catmull-Rom spline with 8 control points evenly spaced around a circle where the distance from the center of each control points is varied by ± r/12 seems about right:
I have to make a SCNCylinder to look like a dynamic pie chart, I am able to make it look like static pie chart by adding texture or applying color to SCNCylinder with below code. However, my pie chart values changes randomly and want to add material with color values occupying percentage portion of the cylinder.
var planet : SCNGeometry
planet = SCNCylinder(radius: 0.2, height: 0.05)
let material = SCNMaterial()
material.diffuse.contents = UIImage(named: "texture.jpg")
//OR to apply single color
material.diffuse.contents = UIColor.red
planet.materials = [material]
let planetNode = SCNNode(geometry: planet)
You can’t recolor arbitrary parts of SCNCylinder with discrete materials. SceneKit defines only one way to decompose a cylinder into separate portions with separate materials (from the docs):
A cylinder contains three SCNGeometryElement objects: one each for its base and top, and one that wraps around its sides. SceneKit can render each element using a different material. For details, see the materials property in SCNGeometry.
That means you can set your planet.materials to an array of three materials, but SceneKit can only use them to color the top, bottom, and sides separately.
So what recourse do you have if you want to create a pie-chart style appearance? OTOH, I can think of two or three directions to investigate:
Do it with images
You mention you’ve already tried something like this — create a static image that looks like a pie chart and assign it to the (top material?) of the cylinder.
There’s nothing preventing you from extending this technique to non-static pie charts. You’ll just need to create your images dynamically (with CoreGraphics, UIGraphicsImageRenderer, etc).
To get your pie chart looking right in 3D you’ll need to create 3 images — a regular pie chart for the top of the cylinder, a reversed version of the same pie chart for the bottom, and a rectangular image with top-to-bottom blocks of color in the same relative proportions as the pie slices that wraps around the sides. It’ll probably take some experimentation to figure out how to format those three images so they line up right.
Do it with custom geometry
If you want a “fully 3D” pie chart (like the ones you see in Pages, Numbers, and Keynote), where each slice is a separate 3D object that can be pulled away from the pie made taller/shorter than other slices, etc, then SCNCylinder is not for you. It only knows how to draw complete cylinders.
There aren’t any built-in SceneKit classes for creating wedge shapes, but if you can work out the math to construct a mesh yourself, you can use SCNGeometrySource and SCNGeometryElement to construct that mesh in SceneKit.
Do it with SCNShape
Custom geometry might be overkill for this task, though. The kind of shape you’re looking for is one of the simpler kinds of 3D geometry — a 2D shape (a sector of a circle) extruded in a third dimension to create a 3D solid (a wedge of a pie, slice of a cake, or whatever other delicious metaphor you prefer).
In SceneKit, there’s an app for that. (Er, a class.) SCNShape takes a 2D UIBezierPath and extrudes it to create a 3D object. You can even apply nice little rounded edges to it. And UIBezierPath lets you create paths using circle arcs.
So, to build a pie chart:
Create several UIBezierPath objects, one for each slice of pie, using the init(arcCenter:radius:startAngle:endAngle:clockwise:) initializer. Use the same center point for all of them (zero is probably fine).
From each Bézier path, create an SCNShape with your preferred extrusion depth. If you want each slice of your pie to have a different flavor color, assign a different material to each shape.
Assemble the slices into a pie by creating an SCNNode to hold each, and placing those nodes at the same position. (The 2D origin of the arc is respected in the 3D coordinate system, so if you set the same node position for different arcs created with the same center they’ll have the same center in 3D.) If you want to be able to move the whole pie together after that, create another SCNNode and make all of the slices its children.
Dangit, now I’m hungry...
Suppose one image like circle image is there. Then I want draw circle over that image, then check two image is same or not in iOS. I tried image matching using CGPoint, but for circle and triangle what to do.
For matching two triangles you may have two choices:
define two areas in each traingle, then calculate areas ratio, they must have the same ratio if they are matched
try to detect three points of each triangle, then calculate the barycentre coordinates
they are invarinat
For circle, if you could easily to represent each circle by a triangle which its points cross that circle, you can find the invariance by the previous steps.
I have a concave polygon I need to draw in OpenGL.
The polygon is defined as a list of points which form its exterior ring, and a list of lists-of-points that define its interior rings (exclusion zones).
I can already deal with the exclusion zones, so a solution for how to draw a polygon without interior rings will be good too.
A solution with Boost.Geometry will be good, as I already use it heavily in my application.
I need this to work on the iPhone, namely OpenGL ES (the older version with fixed pipeline).
How can I do that?
Try OpenGL's tessellation facilities. You can use it to convert a complex polygon into a set of triangles, which you can render directly.
EDIT (in response to comment): OpenGL ES doesn't support tessellation functions. In this case, and if the polygon is static data, you could generate the tessellation offline using OpenGL on your desktop or notebook computer.
If the shape is dynamic, then you are out of luck with OpenGL ES. However, there are numerous libraries (e.g., CGAL) that will perform the same function.
It's a bit complicated, and resource-costly method, but any concave polygon can be drawn with the following steps (note this methos works surely on flat polygons, but I also assume you try to draw on flat surface, or in 2D orthogonal mode):
enable stencil test, use glStencilFunc(GL_ALWAYS,1,0xFFFF)
disable color mask to oprevent unwanted draws: glColorMask(0,0,0,0)
I think you have the vertices in an array of double, or in other form (strongly recommended as this method draws the same polygon multiple times, but using glList or glBegin-glEnd can be used as well)
set glStencilOp(GL_KEEP,GL_KEEP,GL_INCR)
draw the polygon as GL_TRIANGLE_FAN
Now on the stencil layer, you have bits set >0 where triangles of polygon were drawn. The trick is, that all the valid polygon area is filled with values having mod2=1, this is because the triangle fan drawing sweeps along polygon surface, and if the selected triangle has area outside the polygon, it will be drawn twice (once at the current sequence, then on next drawings when valid areas are drawn) This can happens many times, but in all cases, pixels outside the polygon are drawn even times, pixels inside are drawn odd times.
Some exceptions can happen, when order of pixels cause outside areas not to be drawn again. To filter these cases, the reverse directioned vertex array must be drawn (all these cases work properly when order is switched):
- set glStencilFunc(GL.GL_EQUAL,1,1) to prevent these errors happen in reverse direction (Can draw only areas inside the polygon drawn at first time, so errors happening in the other direction won't apperar, logically this generates the intersectoin of the two half-solution)
- draw polygon in reverse order, keeping glStencilFunc to increase sweeped pixel values
Now we have a correct stencil layer with pixel_value%2=1 where the pixel is truly inside the polygon. The last step is to draw the polygon itself:
- set glColorMask(1,1,1,1) to draw visible polygon
- keep glStencilFunc(GL_EQUAL,1,1) to draw the correct pixels
- draw polygon in the same mode (vertex arrays etc.), or if you draw without lighting/texturing, a single whole-screen-rectangle can be also drawn (faster than drawing all the vertices, and only the valid polygon pixels will be set)
If everything goes well, the polygon is correctly drawn, make sure that after this function you reset the stencil usage (stencil test) and/or clear stencil buffer if you also use it for another purpose.
Check out glues, which has tessellation functions that can handle concave polygons.
I wrote a java classe for a small graphical library that do exacly what you are looking for, you can check it here :
https://github.com/DzzD/TiGL/blob/main/android/src/fr/dzzd/tigl/PolygonTriangulate.java
It receive as input two float arrays (vertices & uvs) and return the same vertices and uvs reordered and ready to be drawn as a list of triangles.
If you want to exclude a zone (or many) you can simply connect your two polygones (the main one + the hole) in one by connecting them by a vertex, you will end with only one polygone that can be triangulate like any other with the same function.
Like this :
To better understand zoomed it will look like :
Finally it is just a single polygon.