Inside my custom UITableViewCell I add ShadowView and put all my content on it. When I run it, I see this shadows above the cell, but it hierarchy it's correctly laying below the cell. When I scroll to this cell, it's changing. What can be wrong?
class ShadowView: UIView {
var layer0 = CAShapeLayer()
var layer1 = CAShapeLayer()
var layer2 = CAShapeLayer()
init() {
super.init(frame: .zero)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
override func layoutSubviews() {
super.layoutSubviews()
configShadow()
}
private func configShadow() {
let shadowPath0 = UIBezierPath(roundedRect: bounds, cornerRadius: 16)
layer0.shadowPath = shadowPath0.cgPath
layer0.shadowColor = UIColor.red.withAlphaComponent(0.03).cgColor
layer0.shadowOpacity = 1
layer0.shadowRadius = 5.32
layer0.shadowOffset = CGSize(width: 0, height: 4.72)
layer0.bounds = bounds
layer0.position = center
superview?.layer.insertSublayer(layer0, below: layer)
let shadowPath1 = UIBezierPath(roundedRect: bounds, cornerRadius: 16)
layer1.shadowPath = shadowPath1.cgPath
layer1.shadowColor = UIColor.red.withAlphaComponent(0.04).cgColor
layer1.shadowOpacity = 1
layer1.shadowRadius = 17.87
layer1.shadowOffset = CGSize(width: 0, height: 15.86)
layer1.bounds = bounds
layer1.position = center
superview?.layer.insertSublayer(layer1, below: layer)
let shadowPath2 = UIBezierPath(roundedRect: bounds, cornerRadius: 16)
layer2.shadowPath = shadowPath2.cgPath
layer2.shadowColor = UIColor.red.withAlphaComponent(0.07).cgColor
layer2.shadowOpacity = 1
layer2.shadowRadius = 80
layer2.shadowOffset = CGSize(width: 0, height: 71)
layer2.bounds = bounds
layer2.position = center
superview?.layer.insertSublayer(layer2, below: layer)
}
}
I think your use of insertSublayer(layer0, below: layer) involves a wrong expectation. You can't put this sublayer behind the view's own layer! The correct way to cast a shadow only outside a view using a shape layer is to use a second view, behind the first view, which holds the shape layer. That way, the first view well and truly covers the second view area (so that it is never seen), and only the shadow can "leak out" from behind the first view.
Related
I am trying to make a selection tool. The collision shape is drawn correctly, as you can see in form of the filled box. While the mouse is dragged, I want to draw a green rectangle. However, the box is drawn in the wrong place. What am I missing?
extends Area2D
onready var shape: Shape2D = $CollisionShape2D.shape
onready var collision: CollisionShape2D = $CollisionShape2D
export (Color, RGBA) var color = Color.green
export var stroke_width: float = 1.0
export (bool) var isFilled = true
var startOfDrag: Vector2
var endOfDrag: Vector2
var width: int = 1
var height: int = 1
var isMouseDragged: bool = false
var points: PoolVector2Array
func _process(delta: float) -> void:
if isMouseDragged:
update()
func _draw():
draw_polyline(points , color, stroke_width, isFilled)
func _input(event: InputEvent) -> void:
if Input.is_action_just_pressed("left_mouse_down") and not isMouseDragged:
startOfDrag = get_global_mouse_position()
position = startOfDrag
shape.set_extents(Vector2(1, 1))
isMouseDragged = true
if Input.is_action_just_released("left_mouse_down"):
isMouseDragged = false
handleSelection()
endOfDrag = get_global_mouse_position()
width = abs(startOfDrag.x - endOfDrag.x)
height = abs(startOfDrag.y - endOfDrag.y)
change_rectangle()
func handleSelection() -> void:
shape.set_extents(Vector2(width/2, height/2))
collision.position = Vector2(width/2, height/2)
func change_rectangle() -> void:
points = []
points.append(Vector2(startOfDrag.x, startOfDrag.y))
points.append(Vector2(startOfDrag.x + width, startOfDrag.y))
points.append(Vector2(startOfDrag.x + width, startOfDrag.y + height))
points.append(Vector2(startOfDrag.x, startOfDrag.y + height))
points.append(Vector2(startOfDrag.x, startOfDrag.y))
This is what I see:
startOfDrag = get_global_mouse_position()
position = startOfDrag
The mouse position is in global coordinates. While the position of your object is in local coordinates (you can think of it as coordinates relative to the parent).
Set the global_position instead:
startOfDrag = get_global_mouse_position()
global_position = startOfDrag
By the way, the method to_local converts global coordinates to local coordinates of the node on which you call it. Similarly, there is a to_global method that will convert local coordinates of the node on which you call it to global coordinates.
Keep track of which vectors are in global coordinates and which are in local coordinates.
If there is scaling applied your width and height might also not match. If you run into that, you should be able to fix it with to_local of the CollisionShape2D.
I'm needing to show markers within my circle radius. I'm using Kotlin. I have the circle radius updating with every onCameraIdleListener. The issue I'm having is that I don't understand how to use the for method correctly. My end goal is to have the markers hidden when they are outside of the radius of the circle. so here is the code I have that creates the markers. This is where I store the location key/value:
private var test = mapOf(
"TESTLOCATION" to LatLng(34.695779, -110.344185),
)
this is the code I have that adds the marker to the map:
private fun addTestLocationToMap(){
val placeDetailsMap = mutableMapOf(
"TESTLOCATION" to PlaceDetails(
position = test.getValue("TESTLOCATION"), title = "Test Location", icon = (BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_YELLOW)), snippet = "Test Location"
),
)
placeDetailsMap.keys.map{
with(placeDetailsMap.getValue(it)){
mMap.addMarker(MarkerOptions()
.position(position)
.title(title)
.snippet(snippet)
.icon(icon)
.infoWindowAnchor(infoWindowAnchorX, infoWindowAnchorY)
.draggable(draggable)
.zIndex(zIndex)
.visible(isVisible)
)
}
}
}
Here is the Class I'm using for the addTestLocationToMap:
class PlaceDetails(
val position: LatLng,
val title: String = "Marker",
val snippet: String? = null,
val icon: BitmapDescriptor = BitmapDescriptorFactory.defaultMarker(),
val infoWindowAnchorX: Float = 0.5F,
val infoWindowAnchorY: Float = 0F,
val draggable: Boolean = false,
val zIndex: Float = 0F,
val isVisible: Boolean = true,
val setVisible: Boolean = true)
Here is the Class I have for the Circle:
class Circle(
val center: LatLng,
val radius: Double,
val strokeColor: Int,
val fillColor: Int,
val draggable: Boolean = false)
Here is how I'm adding the circle to the map:
private fun addCircle() {
val newCircle = mutableMapOf(
"CIRCLE" to Circle(
center = mMap.cameraPosition.target,
radius = 241402.0,
strokeColor = Color.RED,
fillColor = 0x00000000
)
)
newCircle.keys.map {
with(newCircle.getValue(it)) {
mMap.addCircle(CircleOptions()
.center(center)
.radius(radius)
.strokeColor(strokeColor)
.fillColor(fillColor)
.draggable(draggable)
)
}
}
}
Here are the private var at the top of the code that updates the lat/lng for the camera:
private var cameraLat: Double = 0.0
private var cameraLng: Double = 0.0
Here is the map of for the Circle:
private var circle = mapOf(
"CIRCLE" to LatLng(cameraLat, cameraLng),)
This is how I'm updating the camera's
mMap.setOnCameraIdleListener {
var cameraLatUpdate = mMap.cameraPosition.target.latitude
var cameraLngUpdate = mMap.cameraPosition.target.longitude
cameraLatLng = mMap.cameraPosition.target
cameraLat = cameraLatUpdate
cameraLng = cameraLngUpdate}
This is how I'm trying to show/hide markers in the radius. Here is:
private lateinit var marker: Marker
This is the code for the radius:
fun addCircleToMap() {
for (marker : LatLng in circle.getValue("CIRCLE") ){
if (SphericalUtil.computeDistanceBetween(circle.getValue("CIRCLE"), test.getValue("TESTLOCATION") ) < 241402.0){
marker.isVisible = true}
This is the error I'm getting "For-loop range must have an 'iterator()' method" This is where I'm stuck at. I have tried to look into iterator but I'm not understanding it. Does my code seem right? Am I doing something wrong with the code? I got the general idea from this comment on another similar question. this code was in java I do believe. I've done my best to try and keep it similar. but I'm not sure on how I can iterator this for loop? Thank you for all your help!
When you call for statement it should be for an iterable collection, but you are calling one unique value, which is circle.getValue("CIRCLE"), I think you should directly assing the value to the marker
val marker = circle.getValue("CIRCLE")
So with some code changes and I was able to successfully hide the markers outside of the circle radius with this code.
private lateinit var testMarkers:MutableList<Marker>
fun testMarkersForLoops(): MutableList<Marker> {
val testMarkers = mutableListOf(
mMap.addMarker(MarkerOptions().position(LatLng(34.695779, -87.634612)).title("testMarker").icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_YELLOW)).visible(false))).toMutableList() return testMarkers
// just make sure to have the visible set to false in order to hide them until their in circle radius
}
fun loopForMarkers(){
val circle = mMap.addCircle(CircleOptions().center(mMap.cameraPosition.target).radius(241402.0).strokeColor(Color.RED).fillColor(0x00000000))
for (marker: Marker in testMarkers ){
if (SphericalUtil.computeDistanceBetween(circle.center, marker.position) < 241402.0){
marker.isVisible = true
Log.i(TAG,"Supposed to set Loves markers within the radius to true testing to see if this runs.")
}
}
}
then adding this within the onMapReady:
mMap.setOnCameraIdleListener {
var cameraLatUpdate = mMap.cameraPosition.target.latitude
var cameraLngUpdate = mMap.cameraPosition.target.longitude
cameraLatLng = mMap.cameraPosition.target
cameraLat = cameraLatUpdate
cameraLng = cameraLngUpdate
mMap.clear()
testMarkers = testMarkersForLoops()
addCircleToMap()
loopForMarkers()
}
you have to call the location list function after the .clear() I was having the .clear() in the wrong spot. Instead of creating the mapOf then using the class PlaceDetails to assign each locations info I just did it with the mutableListOf(). in the for loop just call the mutableListOf name you assigned for it. The radius is in Meters, you can change it to the radius you want. this is roughly 150 mile raidus.
I use the circle.center for the latlng of the center of the circle, having the:
.center(mMap.cameraPosition.target)
Once you place this in the onCameraIdle, this will update the center LatLng with every camera idle.
We currently have a PDF loaded into Forge viewer with multiple markup layers (created using a custom DrawMode), each layers visibility toggleable.
We want to give the user the ability of printing what they currently see (the PDF with the layered markup). I was able to find posts offering potential solutions for printing (using canvas, getScreenshot and MarkupUtils renderToCanvas).
Example post: Autodesk Forge get screenshot with markups
The solution at first looked to be working great but I've noticed only one of our markup layers is ever rendered to the canvas (seemingly the last one added), the other layers are ignored.
All markups are loaded and are visible on screen. Additionally if I hide that layer, it is still printed.
Is there any way to add the markup from all loaded markup layers using renderToCanvas?
Or any potential known workaround?
Any help appreciated. Thanks in advance.
Code snippet of the function I've wrote which works (but loading the most recently added layer only).
export const printViewerToPDF = (markupsCore: MarkupsCore, jsPDF: any) => {
// Create new image
var screenshot = new Image();
// Get the canvas element
var canvas = document.getElementById('snapshot') as HTMLCanvasElement;
// Fit canvas to match viewer
if (canvas) {
canvas.width = markupsCore.bounds.width;
canvas.height = markupsCore.bounds.height;
// Create a context
var ctx = canvas.getContext('2d');
// Clear
if (ctx) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(screenshot, 0, 0, canvas.width, canvas.height);
}
// Screenshot viewer and render to canvas
markupsCore.viewer.getScreenShot(canvas.width, canvas.height, function(
blobUrl: any,
) {
screenshot.onload = function() {
if (ctx) {
ctx.drawImage(screenshot, 0, 0);
}
};
screenshot.src = blobUrl;
});
// Render markup to canvas
setTimeout(function() {
markupsCore.renderToCanvas(ctx, function() {
var pdf = new jsPDF('l', 'px', [canvas.height, canvas.width]);
pdf.addImage(ctx!.canvas, 0, 0, canvas.width, canvas.height);
pdf.save(Date.now().toString() + '.pdf');
});
}, 300);
}
};
Here's what the renderToCanvas method looks like (you can find it in https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/extensions/Markup/Markup.js):
MarkupsCore.prototype.renderToCanvas = function(context, callback, renderAllMarkups) {
var width = this.bounds.width;
var height = this.bounds.height;
var viewBox = this.getSvgViewBox(width, height);
var numberOfScreenshotsTaken = 0;
var markups = [];
var layer;
var onMarkupScreenshotTaken = function () {
if (callback && (++numberOfScreenshotsTaken === markups.length)) {
callback();
}
}.bind(this);
if (renderAllMarkups) {
var svgKeys = Object.keys(this.svg.childNodes);
var layersKeys = Object.keys(this.svgLayersMap);
// Append only markups that their parent layer is contained inside the svg main container.
for (var i = 0; i < svgKeys.length; i++) {
for (var j = 0; j < layersKeys.length; j++) {
layer = this.svgLayersMap[layersKeys[j]];
if (this.svg.childNodes[svgKeys[i]] === layer.svg) {
markups = markups.concat(layer.markups);
}
}
}
} else {
layer = this.svgLayersMap[this.activeLayer] || this.editModeSvgLayerNode;
markups = layer.markups;
}
if (markups.length === 0) {
callback();
} else {
markups.forEach(function(markup) {
markup.renderToCanvas(context, viewBox, width, height, onMarkupScreenshotTaken);
});
}
};
As you can see, if you leave the 3rd parameter undefined or set to false, only markups from the active layer will be rendered. If you set the 3rd parameter to true, markups from all layers should be rendered.
Try stepping into the method yourself and double-check the list of markups towards the end, before markup.renderToCanvas is called for every item in the list.
I'm using geoTools 14.1
I'm trying to plot on an image some points
This is the code I'm using:
double[][] points = new double[8][2];
points[0] = new double[]{45.46433710338643, 9.190417528152478};
points[1] = new double[]{45.46195085146914, 9.189746320685355};
points[2] = new double[]{45.460062304163635, 9.19015527826191};
points[3] = new double[]{45.472950871127445, 9.17363731952788};
points[4] = new double[]{45.4737153001908,9.203728795018847};
points[5] = new double[]{45.4849795331724,9.20162835217198};
points[6] = new double[]{45.48560542313713,9.195953607559215};
points[7] = new double[]{45.48348421787171,9.188765287399292};
final SimpleFeatureType TYPE = DataUtilities.createType("Location",
"location:Point:srid=3857,"+// <- the geometry attribute: Point type
"nome:String," + // <- a String attribute
"id:Integer" // a number attribute
);
FeatureCollection<SimpleFeatureType, SimpleFeature> collection = new DefaultFeatureCollection();
GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null);
SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE);
CoordinateReferenceSystem pointSrc = CRS.decode("EPSG:4326");
CoordinateReferenceSystem targetCRS = CRS.decode("EPSG:3857");
MathTransform transform = CRS.findMathTransform(pointSrc, targetCRS);
for (int i = 0; i < points.length; i++)
{
double[] coords = points[i];
Point point = geometryFactory.createPoint(new Coordinate(coords[0], coords[1]));
Point converted = (Point) JTS.transform( point, transform);
featureBuilder.add(converted);
featureBuilder.add("Punto "+i);
featureBuilder.add(i);
SimpleFeature feature = featureBuilder.buildFeature(""+i);
logger.info(""+feature+" feature.getDefaultGeometry() "+feature.getDefaultGeometry()+ " feature.getDefaultGeometryProperty() "+feature.getDefaultGeometryProperty());
((DefaultFeatureCollection)collection).add(feature);
}
String wellKnownName = "Circle";
Style style = SLD.createPointStyle(wellKnownName,Color.RED,Color.RED,0f,10f);
FeatureLayer fl = new FeatureLayer(collection, style);
fl.setVisible(true);
fl.setSelected(true);
logger.info(""+fl);
mapcontent.addLayer((org.geotools.map.Layer)fl); //"1010177.1917802,5688070.7096562,1029133.5747922,5704122.4855938"
ReferencedEnvelope bounds = new ReferencedEnvelope(1010177.1917802,1029133.5747922,5688070.7096562, 5704122.4855938, targetCRS);
BufferedImage ret = buildImage(mapcontent, 5000, 5000, bounds, Color.white);
ImageIO.write((RenderedImage) ret, "png", new File("/home/angelo/Scrivania/immagineResult.png"));
It seems to me all correct, but the generated image contains no point.
This is the generated image
As you can see it's all white; I was expecting only 8 red circles on the image... Is there any error in my code? Am I doing anything wrong?
Thank you
Angelo
UPDATE: added build image method
public BufferedImage buildImage(final MapContent map, final int imageWidth,final int imageHeight,ReferencedEnvelope bounds,Color bgcolor) {
GTRenderer renderer = new StreamingRenderer();
renderer.setMapContent(map);
renderer.setMapContent(map);
Rectangle imageBounds = null;
ReferencedEnvelope mapBounds = bounds;
try {
if(bounds==null) mapBounds = map.getMaxBounds();
imageBounds = new Rectangle(imageWidth, imageHeight);
} catch (Exception e) {
failed to access map layers
throw new RuntimeException(e);
}
BufferedImage image = new BufferedImage(imageBounds.width, imageBounds.height, BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D gr = image.createGraphics();
int type = AlphaComposite.SRC;
gr.setComposite(AlphaComposite.getInstance(type));
Color c = new Color(bgcolor.getRed(), bgcolor.getGreen(), bgcolor.getBlue(), 0);
gr.setBackground(bgcolor);
gr.setColor(c);
gr.fillRect(0, 0, image.getWidth(), image.getHeight());
type = AlphaComposite.SRC_OVER;
gr.setComposite(AlphaComposite.getInstance(type));
try {
renderer.paint(gr, imageBounds, bounds);
} catch (Exception e) {
throw new RuntimeException(e);
}
return image;
}
After a lot of playing I have found the problem :-) There is no bug in your code! There are in fact 8 red dots in that white image, but they are very hard to find!
As the above image shows at 2000% zoom (and panning along the top edge) you will find a dot (I'm assuming the others are there) - the simple answer is either to make the dots 10 times bigger (100px) or the image much smaller (500x500) and in both cases the dots are immediately visible.
I am new here and sorry if my question is stupid and sorry for my English.
My problem is that I have three layers like on the image below.
The background of "Layer 1" is blue and the color of "Layer 2" is green. Layer 3 has that image with transparent background. I want to remove the second layer according to the image margins. Wherever I move the image I need to remove the second layer. The wanted result is shown on the second image.
You'll want to name your objects so that you can program against them. Because spaces make for bad variable names, let's call your objects as follows:
Layer 1 = blue
Layer 2 = green
Layer 3 = person
Solution
You need a mask, but unlike a normal mask, you want the inverse of the masking shape (ie., inside is hidden as opposed to inside is shown). You can achieve this with BlendMode.ERASE. Then, it's simply a matter of matching position & dimensions of person; whenever you move person, update the location of the mask as well.
function make(color:uint, width:Number, height:Number, x:Number = 0, y:Number = 0, existingShape:Sprite = null):Sprite {
// Helper function to make squares. Will create a new one, or draw on one provided.
var s:Sprite;
if (existingShape != null) {
s = existingShape;
} else {
s = new Sprite();
}
s.graphics.beginFill(color, 1);
s.graphics.drawRect(x, y, width, height);
s.graphics.endFill();
return s;
}
// Layer 1
var blue:Sprite = make(0x3f48cc, 250, 400);
addChild(blue);
// Layer 2
var green:Sprite = make(0x00cc99, 250, 400);
addChild(green);
green.blendMode = BlendMode.LAYER;
// Layer 3
var person:Sprite = make(0xea0502, 20, 100, 20); // arms
make(0xea0502, 60, 20, 0, 20, person); // head and legs
addChild(person);
person.x = 95;
person.y = 150;
// This is the mask. It must be a child of the object it is masking.
var boundary:Sprite = make(0xff00e4, person.width, person.height);
green.addChild(boundary);
boundary.x = person.x;
boundary.y = person.y;
boundary.blendMode = BlendMode.ERASE;
Result