Determine points that are under a sketchOverlay in a map - geometry

I have a map which has a GraphicsOverlay with various points. I have given the user the ability to select a subset of the points by drawing a polygon using the SketchEditor. How can I determine which points have been selected?
Here is a subset of the code to set up the map:
private GraphicsOverlay graphicsOverlayLow;
// Graphics overlay to host sketch graphics
private GraphicsOverlay _sketchOverlay;
var symbolLow = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.Circle, Colors.Green, 10d);
graphicsOverlayLow = new GraphicsOverlay() { Renderer = new SimpleRenderer(symbolLow) };
foreach (var graphic in graphicListLow) // graphicListLow is a List of Points
graphicsOverlayLow.Graphics.Add(graphic);
MyMapView.GraphicsOverlays = new GraphicsOverlayCollection();
MyMapView.GraphicsOverlays.Add(graphicsOverlayLow);
_sketchOverlay = new GraphicsOverlay();
MyMapView.GraphicsOverlays.Add(_sketchOverlay);
I have two buttons, one for starting the drawing of the polygon and one to click when done (this follows the esri example for the SketchEditor). The code for starting is as follows:
private async void SelectButton_Click(object sender, RoutedEventArgs e)
{
try
{
// Let the user draw on the map view using the chosen sketch mode
SketchCreationMode creationMode = SketchCreationMode.Polygon;
Esri.ArcGISRuntime.Geometry.Geometry geometry = await MyMapView.SketchEditor.StartAsync(creationMode, true);
// Create and add a graphic from the geometry the user drew
Graphic graphic = CreateGraphic(geometry);
_sketchOverlay.Graphics.Add(graphic);
}
catch (TaskCanceledException)
{
// Ignore ... let the user cancel drawing
}
catch (Exception ex)
{
// Report exceptions
MessageBox.Show("Error drawing graphic shape: " + ex.Message);
}
}
private Graphic CreateGraphic(Esri.ArcGISRuntime.Geometry.Geometry geometry)
{
// Create a graphic to display the specified geometry
Symbol symbol = null;
switch (geometry.GeometryType)
{
// Symbolize with a fill symbol
case GeometryType.Envelope:
case GeometryType.Polygon:
{
symbol = new SimpleFillSymbol()
{
Color = Colors.Red,
Style = SimpleFillSymbolStyle.Solid,
};
break;
}
Here is the handler for the routine that is called when the user clicks the button signaling that they are done drawing the polygon. This is where I want to determine which points have been selected.
private void CompleteButton_Click(object sender, RoutedEventArgs e)
{
// Cancel execution of the sketch task if it is already active
if (MyMapView.SketchEditor.CancelCommand.CanExecute(null))
{
MyMapView.SketchEditor.CancelCommand.Execute(null);
}
}
Note that I am using the 100.4 SDK for WPF.

This can be accomplished by a spatial query. You will have to use the geometry returned by the sketch editor and use it to perform a spatial query on the layer(s) using geometry filter.
Esri.ArcGISRuntime.Geometry.Geometry geometry = await MyMapView.SketchEditor.StartAsync(creationMode, true);
var queryparameters = new QueryParameters()
{
Geometry = geometry,
SpatialRelationship = SpatialRelationship.Intersects
};
await layer.SelectFeaturesAsync(queryparameters, Esri.ArcGISRuntime.Mapping.SelectionMode.New);

You can use GeometryEngine.Intersects method to check when point graphics intersect, touch, cross the selection polygon.
https://community.esri.com/message/826699-re-determine-points-that-are-under-a-sketchoverlay-in-a-map?commentID=826699#comment-826699

Related

ListView with Groove like quick return header

When scrolling down, Groove moves the header up, outside of the viewable area just like a regular ListView header. When scrolling back up it moves the header back down into the viewable area right away, regardless of the current vertical scroll offset. The header seems to be part of the ListView content because the scrollbar includes the header.
How can this be implemented in a Windows 10 UWP app?
You can do this by utilizing the ListView's internal ScrollViewer's ViewChanged event.
First you got to obtain the internal ScrollViewer. This is the simplest version, but you might want to use one of the many VisualTreeHelper Extensions around to do it safer and easier:
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
var border = VisualTreeHelper.GetChild(MyListView, 0);
var scrollviewer = VisualTreeHelper.GetChild(border, 0) as ScrollViewer;
scrollviewer.ViewChanged += Scrollviewer_ViewChanged;
}
In the EventHandler, you can then change the visibility of your header depending on the scroll direction.
private void Scrollviewer_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
var sv = sender as ScrollViewer;
if (sv.VerticalOffset > _lastVerticalOffset)
{
MyHeader.Visibility = Visibility.Collapsed;
}
else
{
MyHeader.Visibility = Visibility.Visible;
}
}
This is the basic idea. You might wan't to add some smooth animations instead of just changing the visibility.
After looking around a bit and experimentation I can now answer my own question.
One can use an expression based composition animation to adjust the Y offset of the the header in relation to scrolling. The idea is based on this answer. I prepared a complete working example on GitHub.
The animation is prepared in the SizeChanged event of the ListView:
ScrollViewer scrollViewer = null;
private double previousVerticalScrollOffset = 0.0;
private CompositionPropertySet scrollProperties;
private CompositionPropertySet animationProperties;
SizeChanged += (sender, args) =>
{
if (scrollProperties == null)
scrollProperties = ElementCompositionPreview.GetScrollViewerManipulationPropertySet(scrollViewer);
var compositor = scrollProperties.Compositor;
if (animationProperties == null)
{
animationProperties = compositor.CreatePropertySet();
animationProperties.InsertScalar("OffsetY", 0.0f);
}
var expressionAnimation = compositor.CreateExpressionAnimation("animationProperties.OffsetY - ScrollingProperties.Translation.Y");
expressionAnimation.SetReferenceParameter("ScrollingProperties", scrollProperties);
expressionAnimation.SetReferenceParameter("animationProperties", animationProperties);
var headerVisual = ElementCompositionPreview.GetElementVisual((UIElement)Header);
headerVisual.StartAnimation("Offset.Y", expressionAnimation);
};
The OffsetY variable in the animationProperties will drive the animation of the OffsetY property of the header. The OffsetY variable is updated in the ViewChanged event of the ScrollViewer:
scrollViewer.ViewChanged += (sender, args) =>
{
float oldOffsetY = 0.0f;
animationProperties.TryGetScalar("OffsetY", out oldOffsetY);
var delta = scrollViewer.VerticalOffset - previousVerticalScrollOffset;
previousVerticalScrollOffset = scrollViewer.VerticalOffset;
var newOffsetY = oldOffsetY - (float)delta;
// Keep values within negativ header size and 0
FrameworkElement header = (FrameworkElement)Header;
newOffsetY = Math.Max((float)-header.ActualHeight, newOffsetY);
newOffsetY = Math.Min(0, newOffsetY);
if (oldOffsetY != newOffsetY)
animationProperties.InsertScalar("OffsetY", newOffsetY);
};
While this does animate correctly, the header is not stacked on top of the ListView items. Therefore the final piece to the puzzle is to decrease the ZIndex of the ItemsPanelTemplate of the ListView:
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsStackPanel Canvas.ZIndex="-1" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
Which gives this as a result:

Unity Vuforia Google VR - Can't make onPointerEnter to GameObject change material for itself

I have two 3d buttons in my scene and when I gaze into any of the buttons it will invoke OnPointerEnter callback and saving the object the pointer gazed to.
Upon pressing Fire1 on the Gamepad I apply materials taken from Resources folder.
My problem started when I gazed into the second button, and pressing Fire1 button will awkwardly changed both buttons at the same time.
This is the script I attached to both of the buttons
using UnityEngine;
using UnityEngine.EventSystems;
using Vuforia;
using System.Collections;
public class TriggerMethods : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
Material _mat;
GameObject targetObject;
Renderer rend;
int i = 0;
// Update is called once per frame
void Update () {
if (Input.GetButtonDown("Fire1"))
TukarMat();
}
public void OnPointerEnter(PointerEventData eventData)
{
targetObject = ExecuteEvents.GetEventHandler<IPointerEnterHandler>(eventData.pointerEnter);
}
public void OnPointerExit(PointerEventData eventData)
{
targetObject = null;
}
public void TukarMat()
{
Debug.Log("Value i = " + i);
if (i == 0)
{
ApplyTexture(i);
i++;
}
else if (i == 1)
{
ApplyTexture(i);
i++;
}
else if (i == 2)
{
ApplyTexture(i);
i = 0;
}
}
void ApplyTexture(int i)
{
rend = targetObject.GetComponent<Renderer>();
rend.enabled = true;
switch (i)
{
case 0:
_mat = Resources.Load("Balut", typeof(Material)) as Material;
rend.sharedMaterial = _mat;
break;
case 1:
_mat = Resources.Load("Khasiat", typeof(Material)) as Material;
rend.sharedMaterial = _mat;
break;
case 2:
_mat = Resources.Load("Alma", typeof(Material)) as Material;
rend.sharedMaterial = _mat;
break;
default:
break;
}
}
I sensed some logic error and tried making another class to only manage object the pointer gazed to but I was getting more confused.
Hope getting some helps
Thank you
TukarMat() is beeing called on both buttons when you press Fire1. If targetObject is really becoming null this should give an error on first button since it's trying to get component from a null object. Else, it'll change both as you said. Make sure OnPointerExit is beeing called.
Also, it seems you are changing the shared material.
The documentation suggests:
Modifying sharedMaterial will change the appearance of all objects using this material, and change material settings that are stored in the project too.
It is not recommended to modify materials returned by sharedMaterial. If you want to modify the material of a renderer use material instead.
So, try changing the material property instead of sharedMaterial since it'll change the material for that object only.

Draw states in mapControl

I'm writing an application for windows Phone and I'm using a MapControl.
I'd like to be able to paint the US States in different colors.
For example, CA in Red, NV in blue, etc
I Thought about doing Shapes and Polilines, but I can't find the coordinates to use in the shapes to get the different States.
I also tried using the
var found = await MapLocationFinder.FindLocationsAsync("California", new Geopoint(new BasicGeoposition()));
but it doesn't work for finding States.
The best way is to download GeoJSON files from this public repository
https://github.com/johan/world.geo.json/tree/master/countries/USA
Parse the JSON and Create MapPolygon object and add it to map.
public async void RenderState() {
HttpClient client = new HttpClient();
HttpResponseMessage response=await client.GetAsync(new Uri("https://raw.githubusercontent.com/johan/world.geo.json/master/countries/USA/CO.geo.json"));
string json=response.Content.ToString();
JObject obj = JObject.Parse(json);
JObject poly = (JObject)obj["features"][0]["geometry"];
JArray coords = (JArray)poly["coordinates"][0];
MapPolygon polygon = new MapPolygon();
List<BasicGeoposition> points = new List<BasicGeoposition>();
foreach (JArray arr in coords) {
points.Add(new BasicGeoposition() { Latitude = (double)arr[1], Longitude = (double)arr[0] });
}
//Remove last point as it is a duplicate
if (points.Count > 1) {
points.RemoveAt(points.Count - 1);
}
polygon.Path = new Geopath(points);
polygon.StrokeColor = Colors.Red;
polygon.FillColor = Colors.Blue;
this.mMap.MapElements.Add(polygon);
}
This code will render the state of colarado

Best way to convert JTS Geometry from 3D to 2D

We are importing a Multi-Polygon Shapefile with 3D coordinates into oracle spatial using JTS Geometry Suite, GeoTools (ShapefileDataStore) and Hibernate Spatial. In Oracle Spatial we want them to be stored in 2D.
The onyl (and very slow) approach I found is the following, using WKBWriter and WKBReader:
private static Geometry convert2D(Geometry geometry3D) {
// create a 2D WKBWriter
WKBWriter writer = new WKBWriter(2);
byte[] binary = writer.write(geometry3D);
WKBReader reader = new WKBReader(factory);
Geometry geometry2D= null;
try {
geometry2D= reader.read(binary);
} catch (ParseException e) {
log.error("error reading wkb", e);
}
return geometry2D;
}
Does anybody know a more efficient way to convert a geometry from 3D to 2D?
I found a way:
Create a new CoordinateArraySequence which forces to use 2D Coordinate instances
Create a new CoordinateArraySequenceFactory which generates the new custom CoodinateArraySequence
Create a new instance of GeometryFactory which uses the new CoordinateFactory and use it to recreate the geometry:
private static Geometry convert2D(Geometry geometry3D) {
GeometryFactory geoFactory = new GeometryFactory(
geometry3d.getPrecisionModel(), geometry3d.getSRID(), CoordinateArraySequence2DFactory.instance());
if (geometry3D instanceOf Point) {
return geoFactory.createPoint(geometry3D.getCoordinateSequence());
} else if (geometry3D instanceOf Point) {
//...
//...
//...
throw new IllegalArgumentException("Unsupported geometry type: ".concat(geometry3d.getClass().getName());
}
Good luck!!
I did not test the WKBWriter and WKBReader but here is another simple approach:
Create a copy of your geometry
Set all coordinates to 2D
Simple code:
private static Geometry convert2D(Geometry g3D){
// copy geometry
Geometry g2D = (Geometry) g3D.clone();
// set new 2D coordinates
for(Coordinate c : g2D.getCoordinates()){
c.setCoordinate(new Coordinate(c.x, c.y));
}
return g2D;
}

Connect marker with EditPart

I have a graphical editor which extends GraphicalEditorWithFlyoutPalette.
There could be appear different markers, so it would be nice, if there is any possibility to connect the marker with the EditPart.
I think one possibility is to extend the TableViewer and the corresponding cell classes. But perhaps there is a better and more easier way.
I create my test markers like following:
IResource resource = (IResource) input.getAdapter(IResource.class);
try
{
IMarker marker = resource.createMarker(IMarker.PROBLEM);
marker.setAttribute(IMarker.TEXT, "text");
marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
marker.setAttribute(IMarker.MESSAGE, "message");
}
catch (CoreException e)
{
e.printStackTrace();
}
input is my IEditorInput.
In my first attempt, I was trying to extends the ExtendedMarkersView, which fails because it is an internal class.
Another way was to write the view and all corresponding stuff new, but it seems to be senseless.
So I found a work around based on https://stackoverflow.com/a/10501971/390177.
While creating the IMarker, I set additional attributes to link the corresponding data object. With the help of the object I can search for the AbstractGraphicalEditPart with the EditPartRegistry.
After that it is possible to create a selection on the EditPart and reveal to it.
#Override
public void selectionChanged(IWorkbenchPart part, ISelection selection) {
IStructuredSelection s = (IStructuredSelection) selection;
if (s.getFirstElement() instanceof MarkerItem) {
MarkerItem marker = (MarkerItem) s.getFirstElement();
if (marker != null && marker.getMarker() != null) {
IMarker iMarker = marker.getMarker();
AbstractGraphicalEditPart editPart = null;
DataObject object ...
editPart = (AbstractGraphicalEditPart) getGraphicalViewer().getEditPartRegistry().get(object);
if (editPart != null) {
StructuredSelection eSelection = new StructuredSelection(editPart);
getGraphicalViewer().setSelection(eSelection);
// once selected if you want to get it so the
// graphicalviewer scrolls to reveal the part on the
// screen
getGraphicalViewer().reveal(editPart);
}
}
} else {
super.selectionChanged(part, selection);
}
}

Resources