Use GMSCircle as hole of a polygon instead of GMSPath - swift

I have a polygon shape with a square hole punched out, I've been fiddling with trying to do the same but with a circle, GMSCircle, but haven't had any luck.
Would anyone know the proper way to do it?
Here is my current code block for the polygon hole.
let polygon = GMSPolygon()
polygon.path = GMSPath(path: northAmericaPolygon)
polygon.holes = [GMSPath(path: sanFranciscoHole)]
polygon.fillColor = UIColor(displayP3Red: 255, green: 0, blue: 0, alpha: 0.2)
polygon.strokeColor = .black
polygon.strokeWidth = 2
polygon.map = mapView

Related

Issue with invisible Shadow Plane in SceneKit / ARKit

Since a while I am looking around to find answers to my Issue, but cannot find anything that really helps, or explains what is happening. I also over and over checked everything I found on SO, but couldn't find the answer.
The Issue is happening continuously when displaying Objects in the AR World. iEx I place an object to a Plane on the floor, which is my invisible Shadow Plane. Then it depends all on the viewing angle from the device. To clarify, I added to images, which has just a slightly different viewing angle. Have a look what is happening to the shadows:
I would like to have a good shadow all the time and not such artefacts as you can see.
Note: I already played around using the shadowSampleCount, the Bias, and all the other options, that should help to get a proper, low rendering cost shadow.
Here are is the extract of the relevant code for Lighting and Plane, Material, etc
For the SCNLight:
class func directionalLight() -> SCNLight {
let light = SCNLight()
light.type = .directional
light.castsShadow = true
light.color = UIColor.white
light.shadowMode = .deferred
light.shadowSampleCount = 8
light.shadowRadius = 1
// light.automaticallyAdjustsShadowProjection = false
light.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.75)
light.categoryBitMask = -1
return light
}
and how I add it:
func setupLights() {
lightDirectionNode.light = Lighting.directionalLight()
// lightDirectionNode.eulerAngles = SCNVector3(-66.degreesToRadians, 0, 0)
lightDirectionNode.eulerAngles = SCNVector3(0, 90.degreesToRadians, 45.degreesToRadians)
sceneView.scene.rootNode.addChildNode(lightDirectionNode)
}
For the SCNPlane:
class func shadowPlane() -> SCNNode {
let objectShape = SCNPlane(width: 200, height: 200)
objectShape.heightSegmentCount = 2
objectShape.widthSegmentCount = 2
objectShape.cornerRadius = 100
objectShape.cornerSegmentCount = 16
let objectNode = SCNNode(geometry: objectShape)
objectNode.geometry?.firstMaterial?.diffuse.contents = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
objectNode.geometry?.firstMaterial?.colorBufferWriteMask = SCNColorMask(rawValue: 0)
objectNode.physicsBody = Physics.floorPhysicsBody(shape: objectShape)
objectNode.name = "floor"
objectNode.renderingOrder = -10 // renderingOrder // 0
return objectNode
}
and how I add it:
func setupShadowPlane() {
let shadowPlane = NodeFactory.shadowPlane()
// Set the Node's properties
shadowPlane.position = SCNVector3(x: (focusSquare.lastPosition?.x)!, y: (focusSquare.lastPosition?.y)!, z: (focusSquare.lastPosition?.z)!)
shadowPlane.eulerAngles = SCNVector3(-90.degreesToRadians, 0.0, 0.0)
sceneView.scene.rootNode.addChildNode(shadowPlane)
}
What am I doing wrong? Can anyone help?
There are 3 more instance properties to take into consideration:
var shadowRadius: CGFloat { get set }
var shadowCascadeCount: Int { get set }
var shadowCascadeSplittingFactor: CGFloat { get set }
If you don't setup these ones they definitely cause rendering artifacts.
let lightNode = SCNNode()
lightNode.light = SCNLight()
// POSITION OF DIRECTIONAL LIGHT ISN'T IMPORTANT.
// ONLY DIRECTION IS CRUCIAL FOR DIRECTIONAL LIGHTS.
lightNode.rotation = SCNVector4(x: 0, y: 0, z: 0, w: 1)
lightNode.light!.type = .directional
lightNode.light!.castsShadow = true
lightNode.light?.shadowMode = .deferred
/* THREE INSTANCE PROPERTIES TO SETUP */
lightNode.light?.shadowRadius = 3.25
lightNode.light?.shadowCascadeCount = 3
lightNode.light?.shadowCascadeSplittingFactor = 0.09
lightNode.light?.shadowColor = UIColor(white: 0, alpha: 0.75)
scene.rootNode.addChildNode(lightNode)
And one more thing – when Auto Adjust is off:
Light, like a camera, has near and far clipping planes for setup.
lightNode.light?.zNear = 0
lightNode.light?.zFar = 1000000 // Far Clipping Plane is important
Hope this helps.

How do you fade the bottom of an image into the background? [duplicate]

I've read examples around here but I cannot do it the way I desire, somehow my gradient examples are stuck on the middle of the screen, not working as expected.
I have a UICollectionView which fills the whole screen with vertical scroll.
I want the top and bottom of the UICollectionView to be black and the middle to be transparent (since I'm using a black blackgroundColor).
I tried to apply gradients, but somehow I'm failing to accomplish what I want.
Here's my code:
let gradient = CAGradientLayer()
gradient.frame = view.bounds
gradient.colors = [UIColor.black.cgColor, UIColor.clear.cgColor, UIColor.black.cgColor]
gradient.startPoint = CGPoint(x: 1, y: 0)
gradient.endPoint = CGPoint(x: 1, y: 1)
view.layer.mask = gradient
The code above is placing the gradient in the middle of the screen but inverted. It is transparent on top and bottom of the screen and the middle section if fading to complete black.
I'm trying to create something like this:
Thanks for helping
You can achieve that by changing your color line with this:
gradient.colors = [
UIColor(white: 1.0, alpha: 0).cgColor,
UIColor(white: 1.0, alpha: 1).cgColor,
UIColor(white: 1.0, alpha: 0).cgColor
]
Or if you want to have even more control over your gradient, you can also use the code below and play around with the location and/or color alpha values:
let gradient = CAGradientLayer()
gradient.frame = view.bounds
gradient.colors = [
UIColor(white: 1, alpha: 0).cgColor,
UIColor(white: 1, alpha: 1).cgColor,
UIColor(white: 1, alpha: 1).cgColor,
UIColor(white: 1, alpha: 0).cgColor
]
gradient.locations = [0, 0.4, 0.6, 1]
view.layer.mask = gradient
Reason of this from the documentation;
An optional layer whose alpha channel is used to mask the layer’s content.
The layer’s alpha channel determines how much of the layer’s content and background shows through. Fully or partially opaque pixels allow the underlying content to show through but fully transparent pixels block that content.

Swift: Make translucent overlapping lines of the same color not change color when intersecting

Currently I have drawn 2 lines on the screen which are the same color but both have an alpha value less than 1. When these lines intersect, the intersection is a different color than the rest of the lines. There was a previous post addressing the same issue: swift drawing translucent lines, how to make overlapping parts not getting darker? However, this post wasn't sufficiently answered. I draw the lines currently like this:
var points = [CGPoint]()
points = [CGPoint(x: -100, y: 100), CGPoint(x: 100, y: -100)]
let FirstLine = SKShapeNode(points: &points, count: points.count)
FirstLine.strokeColor = UIColor.init(red: 0.25, green: 0.62, blue: 0.0, alpha: 0.5)
FirstLine.lineWidth = 30
addChild(FirstLine)
points = [CGPoint(x: 100, y: 100), CGPoint(x: -100, y: -100)]
let SecondLine = SKShapeNode(points: &points, count: points.count)
SecondLine.strokeColor = UIColor.init(red: 0.25, green: 0.62, blue: 0.0, alpha: 0.5)
SecondLine.lineWidth = 30
addChild(SecondLine)
Here is what it looks like:
I understand why this occurs, but is there any way to make the intersection look the same so it looks much better?
Edit: I have decided to implement #Confused's answer. However, the problem now is that the texture always centres to the middle of the screen. This is an example:
The red cross is in its correct position as it is connecting the specified points together. However, once I make the red cross a texture, it always centres to the middle of the screen (the green cross is the red cross as a texture). Can I use any code that could re-position the texture to its correct position. Note: this code can't just work for this example, I need one that works all the time regardless of the red cross' position.
FINAL EDIT FOR PEOPLE WITH THE SAME PROBLEM
First, setup everything like this:
var points = [CGPoint]()
let crossParent = SKNode()
addChild(crossParent)
Please note THAT YOU MUST create a parent SKNode for the texture otherwise everything on the screen will become the texture and not just the node that you want. Then, add that parent node to the scene.
After, create the lines that you want (in this case the green cross):
//The first line of the green cross
points = [CGPoint(x: -300, y: 300), CGPoint(x: -100, y: 100)]
let FirstLine = SKShapeNode(points: &points, count: points.count)
FirstLine.strokeColor = UIColor.init(red: 0.25, green: 0.62, blue: 0.0, alpha: 1.0)
FirstLine.lineWidth = 30
crossParent.addChild(FirstLine)
Remember to NOT add the first line that you create to the scene, but rather to the parent SKNode that you made at the beginning. Also, set the alpha value to 1.0 for every line that you draw. Then add your other lines:
//The second line of the green cross
points = [CGPoint(x: -100, y: 300), CGPoint(x: -300, y: 100)]
let SecondLine = SKShapeNode(points: &points, count: points.count)
SecondLine.strokeColor = UIColor.init(red: 0.25, green: 0.62, blue: 0.0, alpha: 1.0)
SecondLine.lineWidth = 30
FirstLine.addChild(SecondLine)
Note that you MUST add that line to the first line like this and not to the scene. If you are adding more than one line after adding the first line, then add it to the first line like I have done here too for each consecutive
line that you add.
Now, create the texture like this:
let tex = view?.texture(from: FirstLine)
let cross = SKSpriteNode(texture: tex, color: .clear, size: (tex?.size())!)
cross.alpha = 0.5
addChild(cross)
After doing this, whatever you call cross will be your texture, and you can change the alpha value like I have done here to anything you like and the image will not have varying colors. Remember to then add that texture to the scene.
Finally, you may notice that the texture is not in the same position as where you originally put the points. You can put it back into the same position like this:
cross.position = CGPoint(x: (FirstLine.frame.midX), y: (FirstLine.frame.midY))
Hope this helps :) Thank you to #Confused for the texture part of the program :D
This is a technique. It does not solve your problem, nor directly answer your question. Instead it offers a way to have the desired result, but without the flexibility and inherent nature of lines you actually want.
You can create textures from anything you draw with any number of nodes, with any number of techniques.
You do this (easiest way) by attaching all the drawing elements to a single node, within an SKView space that you have access to, and then render the "parent" node of your drawn objects to a texture.
How does this help?
I'm glad you asked:
You can draw everything at an opacity level of 100%, and render it to a texture, then take that texture of your drawings, put it where you like, and reduce its opacity to any percentage you like, and get an even result. No bright spots where things overlay each other.
Here's code that does all the above:
var points = [CGPoint]()
points = [CGPoint(x: -100, y: 100), CGPoint(x: 100, y: -100)]
let FirstLine = SKShapeNode(points: &points, count: points.count)
FirstLine.strokeColor = UIColor.init(red: 0.25, green: 0.62, blue: 0.0, alpha: 1)
FirstLine.lineWidth = 30
// ^^ Note the FirstLine is not added to the Scene
points = [CGPoint(x: 100, y: 100), CGPoint(x: -100, y: -100)]
let SecondLine = SKShapeNode(points: &points, count: points.count)
SecondLine.strokeColor = UIColor.init(red: 0.25, green: 0.62, blue: 0.0, alpha: 1)
SecondLine.lineWidth = 30
FirstLine.addChild(SecondLine)
// ^^ Note SecondLine being added to FirstLine, and that they both have alpha of 1
// Now the magic: use the view of the SKScene to render FirstLine and its child (SecondLine)
// They are rendered into a texture, named, imaginatively, "tex"
let tex = view.texture(from: FirstLine)
let cross = SKSpriteNode(texture: tex, color: .clear, size: (tex?.size())!)
cross.alpha = 0.5
// ^^ The alpha of the above sprite is set to your original desire of 0.5
// And then added to the scene, with the desired result.
addChild(cross)
and here's the result:
NO! I think is, unfortunately, the answer.
There are the following blend modes, none of which provide the result you're looking for:
case alpha // Blends the source and destination colors by multiplying the source alpha value.
case add // Blends the source and destination colors by adding them up.
case subtract // Blends the source and destination colors by subtracting the source from the destination.
case multiply // Blends the source and destination colors by multiplying them.
case multiplyX2 // Blends the source and destination colors by multiplying them and doubling the result.
case screen // Blends the source and destination colors by multiplying one minus the source with the destination and adding the source.
case replace // Replaces the destination with the source (ignores alpha).
The only option that might work is a custom shader that figures out if it's overlapping itself, somehow. But I have NO CLUE where to even start making something like that, or if it's even possible.
Make the stroke color fully opaque.
Add your path nodes to an SKEffectNode.
Set the alpha of the effect node to the desired value.
Put the effect node into your main scene.
While doing this you can also put all lines in one shape node:
let path = CGMutablePath()
path.move( to: CGPoint(x: -100, y: 100))
path.addLine(to: CGPoint(x: 100, y: -100))
path.move( to: CGPoint(x: 100, y: 100))
path.addLine(to: CGPoint(x: -100, y: -100))
let shape = SKShapeNode(path: path)
shape.strokeColor = UIColor(red: 0.25, green: 0.62, blue: 0.0, alpha: 1)
shape.lineWidth = 30
let effect = SKEffectNode()
effect.addChild(shape)
effect.alpha = 0.5
addChild(effect)
The problem is you are doing the alpha blend at the color level, do the alpha blending at the node level
var points = [CGPoint]()
var cross = SKEffectNode()
points = [CGPoint(x: -100, y: 100), CGPoint(x: 100, y: -100)]
let FirstLine = SKShapeNode(points: &points, count: points.count)
FirstLine.strokeColor = UIColor.init(red: 0.25, green: 0.62, blue: 0.0, alpha: 1)
FirstLine.lineWidth = 30
cross.addChild(FirstLine)
points = [CGPoint(x: 100, y: 100), CGPoint(x: -100, y: -100)]
let SecondLine = SKShapeNode(points: &points, count: points.count)
SecondLine.strokeColor = UIColor.init(red: 0.25, green: 0.62, blue: 0.0, alpha: 1)
SecondLine.lineWidth = 30
cross.addChild(SecondLine)
cross.alpha = 0.5
addChild(cross)

CAShapeLayer background-color fading to sides in Swift

I have created a clickable diagram with CAShapeLayers and UIBezierPaths. These shapes have a background-color that I want to fade out to transparent on the sides/edges. All CAShapeLayers have different shapes. Is there a way to achieve this in Swift?
I attached a simple example image of what I'm trying to do:
Right now, I'm creating the CAShapeLayers as follows:
var path = UIBezierPath()
path.moveToPoint(CGPointMake(20, 30))
path.addLineToPoint(CGPointMake(40, 30))
path.addLineToPoint(CGPointMake(50, 60))
path.addLineToPoint(CGPointMake(120, 180))
path.closePath()
var layer = CAShapeLayer()
layer.path = path.CGPath
layer.fillColor = UIColor(red: 255, green: 0, blue: 0, alpha: 0.5).CGColor
layer.hidden = true
baseImg.layer.addSublayer(layer)
Is there a way to add a CIGaussianBlur or a UIBlurEffect to these shapes?

How to fill color outside the circle on google map using Swift?

I want the red circle just have the border (no red in centre) and have the rest outside the circle darkened?
I have a issue about that. Could you help me solve it?
With google maps for this, you should do the following steps
Create a GMSCircle object
Set stroke color and fill color for the
circle
Set map for the circle object
Example code:
let circleCenter = CLLocationCoordinate2DMake(9.931233, 76.267303)//change to your center point
let circ = GMSCircle(position: circleCenter, radius: 5000)//radius in meters
circ.fillColor = UIColor(red: 0.35, green: 0, blue: 0, alpha: 0.05)
circ.strokeColor = UIColor.redColor()
circ.strokeWidth = 1
circ.map = mapView //your map view in the UI