As the title says. The labels I add to the MapLayout ("top" and "bottom") are not really fixed to the given coordinate. Am I missing something to avoid this effect (see screen record below).
my sample code:
final MapContainer mapContainer = new MapContainer(API_KEY, false);
Container actual = new Container();
actual.setLayout(new MapLayout(mapContainer, actual));
Form f = new Form("Maps", new LayeredLayout());
f.add(mapContainer);
f.add(actual);
String[] coordinates = new String[] {
"50.963642, 7.121855"
};
List<MapContainer.MapObject> addedMarkers = new ArrayList<>();
List<Coord> coords = new ArrayList<>();
EncodedImage ei = EncodedImage.createFromImage(
FontImage.createMaterial(FontImage.MATERIAL_GPS_FIXED, f.getUnselectedStyle())
, false);
for(String cStr : coordinates) {
Coord c = toCoordinate(cStr);
MapContainer.MapObject obj = mapContainer.addMarker(ei, c, "Marker", "Long text", (evt) -> {
log.p("clicked on marker" + c);
Component cmp1 = new Label("top");
actual.addComponent(c, cmp1);
MapLayout.setHorizontalAlignment(cmp1, 0.5f);
MapLayout.setVerticalAlignment(cmp1, 1f);
Component cmp2 = new Label("bottom");
actual.addComponent(c, cmp2);
MapLayout.setHorizontalAlignment(cmp2, 0.5f);
MapLayout.setVerticalAlignment(cmp2, 0f);
});
coords.add(c);
addedMarkers.add(obj);
}
f.revalidate();
f.show();
Try using this new API https://www.codenameone.com/blog/map-component-positioning-revisited.html
It works better than the older map layout approach as it converts components to markers back & forth.
Related
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 testing adding a collection of points to a map utilizing the Geotools API. I've been following this example as best I could Problem creating a point and adding it to FeatureCollection, as the example code is old, and things like FeatureCollections is deprecated. I tried using DefaultFeatureCollection instance instead, and I am not sure if I am using it correctly, and that is why the points do not appear on the map. What am I doing wrong? Here is some of my code:
private void plotMarkers() {
final SimpleFeatureType TYPE = this.createFeatureType();
final SimpleFeatureBuilder BLDR = new SimpleFeatureBuilder(TYPE);
DefaultFeatureCollection features = new DefaultFeatureCollection();
// arbitrary start position
Coordinate pos = new Coordinate(0, 0);
final double pointSpacing = 1.0;
String title = "Test";
features.add(creatureFeature(BLDR, pos, title));
// display points on screen
Style style = SLD.createPointStyle("circle", Color.RED, Color.RED, 1.0f, 5.0f);
Layer layer = new FeatureLayer(features, style);
this.getMapContent().addLayer(layer);
}
Maybe this can help you to make it work
private MapContent map;
private static Style pointStyle = SLD.createPointStyle("Circle", Color.RED, Color.RED, 0.5f, POINT_SIZE);
public static void CreatePoints(double X, double Y){
createPointLayer();
createFeatures(X,Y);
}
static void createFeatures(double X, double Y) {
Point point = geometryFactory.createPoint(new Coordinate(X, Y));
pointCollection.add(SimpleFeatureBuilder.build(pointType, new Object[]{point}, null));
//create map layer event
MapLayerEvent mple = new MapLayerEvent(pointLayer, MapLayerEvent.DATA_CHANGED);
//create maplayer list event
MapLayerListEvent mplle = new MapLayerListEvent(map, pointLayer, map.layers().indexOf(pointLayer), mple);
okvir.mapPane.layerChanged(mplle);
System.out.println(MessageFormat.format("Created Point: {0}", point));
}
private static void createPointLayer() {
if (pointType == null) {
pointFeatureTypeBuilder.setName("PointCreated");
pointFeatureTypeBuilder.setCRS(map.getCoordinateReferenceSystem());
pointFeatureTypeBuilder.add("the_geom", Point.class);
pointType = pointFeatureTypeBuilder.buildFeatureType();
pointCollection = new DefaultFeatureCollection(null, pointType);
}
pointLayer = new FeatureLayer(pointCollection, pointStyle);
map.addLayer(pointLayer);
}
I use this code to add custom marker to BING map control. The Map component can't draw Image(), but text works fine. Am I wrong?
private void AddMarkerToMap(double Latitude, double Longitude, string Name)
{
Image markerImg = new Image { Width = 63, Height = 46 };
Uri imgUri = new Uri("Images/GeoPin.png", UriKind.RelativeOrAbsolute);
if (imgUri == null)
{
throw new Exception("Image can't be find");
}
markerImg.Source = new BitmapImage(imgUri);
markerImg.Tag = Name;
//markerImg.Tap += delegate
//{
// // handle tap
//};
var overlay = new MapOverlay
{
PositionOrigin = new Point(0.5, 0.5),
GeoCoordinate = new GeoCoordinate(Latitude, Longitude),
Content = markerImg,
//Content = Name,
};
var mapLayer = new MapLayer { overlay };
MyMap.Layers.Add(mapLayer);
}
If you want to add a pin to Map, use MapIcon class. This can display images as well as text.
private void AddMapIcon()
{
MapIcon MapIcon1 = new MapIcon();
MapIcon1.Location = new Geopoint(new BasicGeoposition() { Latitude = 47.620, Longitude = -122.349 });
MapIcon1.NormalizedAnchorPoint = new Point(0.5, 1.0);
MapIcon1.Title = "Space Needle";
MapIcon1.Image = RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///Assets/customicon.png"));
MapControl1.MapElements.Add(MapIcon1);
}
Does MapIcon present in Windows Phone 8 SDK?
You could use the Phone.Controls.Toolkit in order to have a custom Pushpin as an image on your map.
Reference: Image as pushpin on maps - Windows phone 8
In my application I have a map for which the first thing I do (on launching) is to add a custom MapLayer (which I populate with many MapOverlays/pushpins).
When I browse to another page of the app and then return to the map page, everything (ie the MapLayer that was drawn on my map) is gone.
It takes time to add it all over again each time the user navigates to the map page so I would like it to be fixed, drawn/added just once.
Any suggestions?
edit, added the code [I removed some details, the structure remains the same]:
private async void drawStations()
{
SQLiteAsyncConnection conn = new SQLiteAsyncConnection("stasy.sqlite");
List<line1_stations> lines = await conn.QueryAsync<line1_stations>("select *...");
Microsoft.Phone.Maps.Controls.MapLayer layer = new Microsoft.Phone.Maps.Controls.MapLayer();
Pushpin p;
foreach (line1_stations a in lines)
{
double sLat = Convert.ToDouble(a.lat);
double sLon = Convert.ToDouble(a.lon);
p = new Pushpin();
p.Location = new GeoCoordinate(sLat, sLon);
p.Tap += img_Tap;
p.Content = "...";
p.Foreground = new SolidColorBrush(Colors.Transparent);
p.Width = 30;
p.Height = 30;
MapOverlay overlay1 = new MapOverlay();
overlay1.Content = p;
overlay1.GeoCoordinate = new GeoCoordinate(sLat, sLon);
overlay1.PositionOrigin = new Point(0.0, 1.0);
layer.Add(overlay1);
}
myMap.Layers.Add(layer);
}
You can try to create your MapLayer as a public property in App.xaml.cs and set it only when your app is running first time.
Then create an instance of app inside page with your map and add your MapLayer to your Map layers inside OnNavigatedTo event.
Define a flag in app level. here is the sample
// In App.xaml.cs
public static bool IsLaunched = false;
private void Application_Launching(object sender, LaunchingEventArgs e)
{
IsLaunched =true;
}
//In your map screen
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if(App.IsLaunched)
{
drawStations();
//Set App flage to false
App.IsLaunched = false;
}
}
private async void drawStations()
{
SQLiteAsyncConnection conn = new SQLiteAsyncConnection("stasy.sqlite");
List<line1_stations> lines = await conn.QueryAsync<line1_stations>("select *...");
Microsoft.Phone.Maps.Controls.MapLayer layer = new Microsoft.Phone.Maps.Controls.MapLayer();
Pushpin p;
foreach (line1_stations a in lines)
{
double sLat = Convert.ToDouble(a.lat);
double sLon = Convert.ToDouble(a.lon);
p = new Pushpin();
p.Location = new GeoCoordinate(sLat, sLon);
p.Tap += img_Tap;
p.Content = "...";
p.Foreground = new SolidColorBrush(Colors.Transparent);
p.Width = 30;
p.Height = 30;
MapOverlay overlay1 = new MapOverlay();
overlay1.Content = p;
overlay1.GeoCoordinate = new GeoCoordinate(sLat, sLon);
overlay1.PositionOrigin = new Point(0.0, 1.0);
layer.Add(overlay1);
}
myMap.Layers.Add(layer);
}
i am following the example
Nokia blog but my problem is ,
1> i need to add image to the location point instead of color
2> i want to show detail information in the popup like Google map
May this help you.
Here i had use textblock to show custom data. Background image for a stack panel
Private void ShoeCustomPushPuin()
{
Pushpin pushPin = null;
StackPanel stackPanel = null;
TextBlock txtblkDownloadSpeed = null;
TextBlock txtblkUploadSpeed = null;
GeoCoordinate cordinates = null;
try
{
cordinates = new GeoCoordinate();
pushPin = new Pushpin();
stackPanel = new StackPanel();
txtblkDownloadSpeed = new TextBlock();
txtblkUploadSpeed = new TextBlock();
cordinates.Latitude = Your latitude value;
cordinates.Longitude = your longitude value;
txtblkUploadSpeed.Text = your data;
txtblkDownloadSpeed.Text =your data;
ImageBrush imgbrush= new ImageBrush
{
ImageSource = new BitmapImage(new Uri("your background image path", UriKind.Relative)),
};
stackPanel.Background = imgbrush;
stackPanel.Children.Add(txtblkDownloadSpeed);
stackPanel.Children.Add(txtblkUploadSpeed);
pushPin.Content = stackPanel;
pushPin.GeoCoordinate = cordinates;
MapOverlay overlay = new MapOverlay
{
GeoCoordinate = cordinates,
Content = pushPin
};
MapLayer layer = new MapLayer();
layer.Add(overlay);
mapHistory.Center = cordinates;
mapHistory.Layers.Add(layer);
}
catch (Exception ex)
{
}
}