How to put multiple circle overlays on a WP7 Bing Map control? - xaml

I want to put a number of (transparent) circles on a Bing Map Control as overlays. Think about a "blast radius" or "sphere of influence" kind of thing. I'll need at least two dozen of these circles on the map, together with some other polygons, so making sure performance does not suffer and the maps continues to be easily manipulative seems key here.
So far I can think of three options (of which I tried two):
Add n-sided MapPolygon instances to the map for each circle. Tried this, and works fine in principle. However, the number of vertices per polygon is a bit of pickle. Too little, and when you zoom in it looks hideous. Too many, and performance will start to suffer.
Add Pushpin instances for each circle, and style/template them as circle that are centered around the pushpin location. Seems to work, except that the size of the cicle is then fixed in screen size, not map size. So when you zoom, the circles stay the same size on screen, while they should zoom with the map. Can you bind the size of Ellipse control (in the template in the style I use) to the Zoom of the parent map control in some way..?
Create a custom subclass of MapShapeBase to represent each circle. This implementation could dynamically change the number of vertices used to draw the polygon depending on whether the shape is visible on the map or not (=inside current view port) and what the zoom level is. That is, if map shapes have access to this information. I haven't tried this option yet.
What have you used? What would you use? How would you work around the problems mentioned above, especially binding a property of a control in a template used in a style to a parent control property using XAML? Or do you have any other options I could try to get this to work?

In RunKeeper we used the first option and bound the Locations property to a LocationCollection with 360 points created as follows:
protected void UpdateAccuracyCircle()
{
var location = this.CurrentLocation;
if (null != location)
{
var lat = location.Latitude * (Math.PI / 180);
var lng = location.Longitude * (Math.PI / 180);
var d = (this.Accuracy / 1000.0) / Constants.EarthRadius;
var circle = new LocationCollection();
for (int x = 0; x <= 360; x++)
{
var brng = x * (Math.PI / 180);
var latRadians =
Math.Asin(
Math.Sin(lat) *
Math.Cos(d) +
Math.Cos(lat) *
Math.Sin(d) *
Math.Cos(brng));
var lngRadians =
lng +
Math.Atan2(
Math.Sin(brng) * Math.Sin(d) * Math.Cos(lat),
Math.Cos(d) - Math.Sin(lat) * Math.Sin(latRadians));
circle.Add(
new GeoCoordinate(
latRadians * (180 / Math.PI),
lngRadians * (180 / Math.PI)));
}
Dispatcher.BeginInvoke(() => this.AccuracyCircle = circle);
}
}
In this instance we're only dealing with one circle (for the accuracy indication), so might not be particularly efficient if you need multiple circles.
Given that the logic for creating the circle is in code in this example, I think you could easily adjust the logic to use more/fewer points based on the ZoomLevel to meet option 3.

I suggest you move away from the Bing Map Controls and start using the ESRI Silverlight / WP7 Toolkit. They have much more controls available that you can use out of the box.
http://help.arcgis.com/en/arcgismobile/10.0/apis/windowsphone/
Here are all the samples: http://help.arcgis.com/en/arcgismobile/10.0/apis/windowsphone/samples/start.htm
You will need an account to download the SDK, but it's free (to register and download).

I'd suggest using a canvas as an overlay with a transparent background and then add ellipse objects to that, using a similar technique as described here.
Only trick will be to get the aspect ratio of the canvas aligned with the map control as it's displayed / updated and the positioning of the ellipses relative to the coordinates your aiming for.

Related

libgdx camera position using viewport

I am rather experiences libgdx developer but I struggle with one issue for some time so I decided to ask here.
I use FillViewport, TiledMap, Scene2d and OrtographicCamera. I want the camera to follow my player instance but there are bounds defined (equal to mapsize). It means that camera will never ever leave outside of map, so when player comes to an end of the map camera stops following and he goes to the edge of the screen itself. Maybe sounds complicated but it's simple and I am sure that you know what I mean, it's used in every game.
I calculated 4 values:
minCameraX = camera.viewportWidth / 2;
minCameraY = camera.viewportHeight / 2;
maxCameraX = mapSize.x camera.viewportWidth / 2;
maxCameraY = mapSize.y - camera.viewportHeight / 2;
I removed not necessary stuff like unit conversion, camera.zoom etc. Then I set the camera position like this:
camera.position.set(Math.min(maxCameraX, Math.max(posX, minCameraX)), Math.min(maxCameraY, Math.max(posY, minCameraY)), 0);
(posX, posY is player position) which is basically setting camera to player position but if it's to high or too low it sets it to max or min defined before in right axis. (I also tries MathUtils.clamp() and it works the same.
Everything is perfect until now. Problem occures when aspect ratio changes. By default I use 1280x768 but my phone has 1280x720. Because of that bottom and top edges of the screen are cut off because of the way how FillViewport works. Because of that part of my map is cut off.
I tried to modify maximums and minimums, calculate differences in ratio and adding them to calculations, changing camera size, different viewports and some other stuff but without success.
Can you guys help?
Thanks
I tried solution of noone and Tenfour04 from comments above. Both are not perfect but I am satisified enough i guess:
noone:
camera.position.x = MathUtils.clamp(camera.position.x, screenWidth/2 + leftGutter, UnitConverter.toBox2dUnits(mapSize.x) - screenWidth/2 + rightGutter);
camera.position.y = MathUtils.clamp(camera.position.y, screenHeight/2 + bottomGutter, UnitConverter.toBox2dUnits(mapSize.y) - screenHeight/2 - topGutter);
It worked however only for small spectrum of resolutions. For strange resolutions where aspect ratio is much different than default one I've seen white stripes after border. It means that whole border was printer and some part of the world outside of border. I don't know why
Tenfour04:
I changed viewport to ExtendViewport. Nothing is cut off but in different aspect ratios I also can see world outside of borders.
Solution for both is to clear screen with same color as the border is and background of level separatly which gave satisfying effect in both cases.
It stil has some limitations. As border is part of the world (tiled blocks) it's ok when it has same color. In case border has different colors, rendering one color outside of borders won't be a solution.
Thanks noone and Tenfour04 and I am still opened for suggestions:)
Here are some screenshots:
https://www.dropbox.com/sh/00h947wkzo73zxa/AAADHehAF4WI8aJ8bu4YzB9Va?dl=0
Why don't you use FitViewport instead of FullViewport? That way it won't cut off your screen, right?
It is a little bit late, but I have a solution for you without compromises!
Here width and height are world size in pixels. I use this code with FillViewport and everything works excellent!
float playerX = player.getBody().getPosition().x*PPM;
float playerY = player.getBody().getPosition().y*PPM;
float visibleW = viewport.getWorldWidth()/2 + (float)viewport.getScreenX()/(float)viewport.getScreenWidth()*viewport.getWorldWidth();//half of world visible
float visibleH = viewport.getWorldHeight()/2 + (float)viewport.getScreenY()/(float)viewport.getScreenHeight()*viewport.getWorldHeight();
float cameraPosx=0;
float cameraPosy=0;
if(playerX<visibleW){
cameraPosx = visibleW;
}
else if(playerX>width-visibleW){
cameraPosx = width-visibleW;
}
else{
cameraPosx = playerX;
}
if(playerY<visibleH){
cameraPosy = visibleH;
}
else if(playerY>height-visibleH){
cameraPosy = height-visibleH;
}
else{
cameraPosy = playerY;
}
camera.position.set(cameraPosx,cameraPosy,0);
camera.update();

JSX (Photoshop) - document resolution in dpi

I'm working with a jsx script in Photoshop that resizes images to a specific size. The resolution is set at 200 dpi. After running the script, I can check this under Image > Image Size.
Problem is, depending on the image, it initially tends to show the resolution in dots/cm instead of dots/inch. The number itself is correct either way, but I'd like to see it mentioned there as the latter. Is there a way to realize this in JSX?
Thanks!
J
The easy way is to open your Info Panel by going to Window > Info, and then click on the x/y coordinates dropdown in the Info Panel and select inches. The dropdown is the + toward the lower-left of the panel, with the little down arrow at the bottom right of the + symbol (The plus is actually an x axis and y axis representing a coordinate plane). After that, when you check under Image > Image Size, it should show you all information in inches instead of centimeters. This should also show you inches anywhere else you look in Photoshop's interface, too, such as the rulers.
An exception would be that when using selection tools, such as the marquee tool with a setting like "fixed size" selected, you can override the units setting by typing in another unit in the Width and Height sections at the top of the window. You can even mix and match units, making a precise selection that is, for example, exactly 250 pixels (px in the Width setting) by 30 points (pt in the Height setting). And when you check your image size, it should still show you results in inches.
And finally, to answer your question as it was asked, the following code will change your rulerUnits preference without opening the Info Panel.
#target Photoshop
preferences.rulerUnits = Units.INCHES;
Note that if you want to write other scripts, you can change the rulerUnits to whatever units the script calls for, and then at the end of the script put your units back the way you had them.
#target Photoshop
// Save the original rulerUnits setting to a variable
var originalRulerUnits = preferences.rulerUnits;
// Change the rulerUnits to Inches
preferences.rulerUnits = Units.INCHES;
//
// Do magical scripty stuff here...
//
// Restore the original setting
preferences.rulerUnits = originalRulerUnits;
// List of rulerUnits settings available
// Units.CM
// Units.INCHES
// Units.MM
// Units.PERCENT
// Units.PICAS
// Units.PIXELS
// Units.POINTS

How to zoom a pdf to the mouse position in javafx 2

I have to zoom a pdf-file thats inside of a ScrollPane.
The ScrollPane itself is inside of a StackPane.
In the beginning I scale my pdf to fit the width of my ScrollPane. As a result of that the pdf-height doesn't fit the ScrollPanes height.
I already managed to zoom, by changing my scaleFactor when using the mousewheel. Unfortunately I can't zoom into a specific point.
I guess I have to change the ScrollPanes values depending on the mouse coordinates, but I just can't find the correct calculation. Can somebody please help me?
For example I tried
scrollPane.setVvalue(e.getY() / scrollPane.getHeight())
With this line of code my view just jumps up or down, depending on whether I click on the upper bound or the lower bound of my viewport.
I also understand that it has to behave like that, but I can't figure it out what has to be added/changed.
I use Jpedal to display my pdf
Hope you understand what I am looking for.
Tell me if you need more information.
Edit:
Here is a snipped of how I managed to drag.
eventRegion.addEventFilter(MouseEvent.MOUSE_PRESSED, e -> {
dragStartX = e.getX();
dragStartY = e.getY();
});
eventRegion.addEventFilter(MouseEvent.MOUSE_DRAGGED, e -> {
double deltaX = dragStartX - e.getX();
double deltaY = dragStartY - e.getY();
scrollPane.setHvalue(Math.min(scrollPane.getHvalue() + deltaX / scrollPane.getWidth(), scrollPane.getHmax()));
scrollPane.setVvalue(Math.min(scrollPane.getVvalue() + deltaY / scrollPane.getHeight(), scrollPane.getVmax()));
e.consume();
});
I think zooming to the mouse position could be done in a similar way, by just setting the Hvalue and Vvalue.
Any ideas how I can calculate these values?
This example has JavaFX 8 code for a zoomable, pannable ScrollPane with zoom to mouse pointer, reset zoom and fit to width of a rectangle which can really be any Node. Be sure to check out the answer to the question to get fitWidth() to work correctly. I am using this solution for an ImageView now, and it is slick.
just for all related questions about "zooming where the mouse is".
I had the same problem and I came up with the following code snippet.
public void setZoom(final double x, final double y, final double factor) {
// save the point before scaling
final Point2D sceneToLocalPointBefore = this.sceneToLocal(x, y);
// do scale
this.setScaleX(factor);
this.setScaleY(factor);
// save the point after scaling
final Point2D sceneToLocalPointAfter = this.sceneToLocal(x, y);
// calculate the difference of before and after the scale
final Point2D diffMousePoint = sceneToLocalPointBefore.subtract(sceneToLocalPointAfter);
// translate the pane in order to point where the mouse is
this.setTranslateX(this.getTranslateX() - diffMousePoint.getX() * this.getScaleX());
this.setTranslateY(this.getTranslateY() - diffMousePoint.getY() * this.getScaleY());
}
The basic idea is to move the underlying Pane to that point where it was before scaling. Important is the fact, that we calculate the mouse position to the local coordinate system of the Pane. After scale we do this just another time and calculate the difference. Once we know the difference we are able to move back the Pane. I think this solution is very easy and straightforward.
My setup in JavaFX is following: I have a javafx.scene.layout.BorderPane as root for my javafx.scene.Scene. In the center I put a Pane. This will be the Pane where I act on (i.e. put other Nodes in..zoom, move..etc.) If anyone is interested in how I actually did it, just mail me.
Good programming!

Dynamic resizing of the body (LibGDX)

I have a circle-shaped dynamic body and I need to resize it during the game (It appears like a point, then it grows to a circle and after that it starts moving). How should I do that?
I have an idea - it's to use some animation (Circle has the same radius, but due to animation it looks like the circle grows), but I'm not sure if it's right way or not. (Besides I don't know how to realize it)
For scaling circle, if you are using sprite just scale it sprite.setScale(float), if your sprite is attached to Box2d Circle-shape then get the Body's shape and set the radius
Shape shape = body.getFixture().getShape;
shape.setRadius(radiusValue);
and if you are using ShapeRenderer just multiply the points of ShapeRenderer.
I assume that you are talking about a Box2D body.
It is not possible to change a circle-shaped fixture with Box2D. Box2D is a rigid body simulator. What you would have to do is destroy the fixture and replace it with a smaller/bigger version of the circle. But this will cause a lot of problems, since you cannot destroy a fixture when there is still a contact for example.
It would be better to keep the circle the same size and just simulate a change in size with an animation of a texture on top.
If you cannot simulate that, then maybe try the following approach: Have several versions of that circle in different sizes and keep them on top of each other. Implement a ContactFilter which will only cause contacts for the one circle which is currently "active".
Inside any Object class with box2d, I use the following for dynamic resizing:
public void resize(float newradius) {
this.body.destroyFixture(this.fixture);
fixtureDef.density = (float) (this.mass/(Math.PI*newradius*newradius));
this.radius = newradius;
CircleShape circle = new CircleShape();
circle.setRadius(newradius);
this.fixtureDef.shape = circle;
circle.dispose();
this.fixture = body.createFixture(fixtureDef);
this.fixture.setUserData(this);
}
You can also see the following topic: How to change size after it has been created

How do you measure how far the map moved?

In my mapView:regionDidChangeAnimated method I'm making a call to find places on the map but I only want to make the call if the map has moved a significant amount.
Here is scenario:
User moves map or map load
HTTP call to get find places
Add places to the map.
PROBLEM! User clicks on an annotation opening the title bubble and it's close to the edge so it moves the map. Since the loading of data is tied to the map move event the marker disappears and is re-added.
How should I watch both the span and the center point for change?
#Scott Thanks for the visibleMapRect idea. This is what I have working so far, it still needs to account for zooming in and out.
MKMapRect newRect = _mapView.visibleMapRect;
MKMapRect oldRect = currentRect;
float leftBoundry = (newRect.origin.x-(newRect.size.width/4));
float rightBoundry = (newRect.origin.x+(newRect.size.width/4));
float topBoundry = (newRect.origin.y-(newRect.size.height/4));
float bottomBoundry = (newRect.origin.y+(newRect.size.height/4));
NSLog(#"Origin x %f, y %f", oldRect.origin.x, oldRect.origin.y);
NSLog(#"Boundries left %f, top %f, right %f, bottom %f", leftBoundry, topBoundry, rightBoundry, bottomBoundry);
if (oldRect.origin.x < leftBoundry || oldRect.origin.x > rightBoundry || oldRect.origin.y < topBoundry || oldRect.origin.y > bottomBoundry) {
[self loadLocations];
currentRect = newRect;
}
Hmm. It sounds like you're refreshing your map by removing all annotations, and then (re-)displaying all annotations that fall within the visibleMapRect – and that solving this problem may require a more nuanced approach to updating the map.
One approach might be to use MKMapRectIntersection to identify the overlap between your "old" and "new" visibleMapRects, and (if there is one) exclude the annotations in this region from being removed or re-added. Or, you could calculate the L-shaped area that's scrolling on-screen and only make an HTML call for data within that region.
Or you could just check whether the map's "old" center is still within visibleMapRect, and if so arbitrarily decide that the map hasn't moved a significant amount. That may leave you with areas on-screen that should have annotations but don't, though.
Or, finally, you could just store the coordinate of the user-selected annotation, and if that coordinate is still on-screen after the map moves, find it and re-select the annotation.