How do you remove a vertex from a polygon with multiple paths? - google-maps-api-3

In googlemaps api, when editing a polygon with multiple paths, removeAT eliminates the wrong vertex
For simple polygons, the removeAT will remove the correct vertex, but for multiple path polygons, it seems to remove only the vertex number from the first path.
Given this definition of a polygon for multiple paths:
var blockpolygon = newgoogle.maps.Polygon({
paths: [blockcoords0,blockcoords1,blockcoords2,blockcoords3,blockcoords4,blockcoords5]
});
where the paths are previously defined, for example:
var blockcoords4 = [{lat:51.799693211411,lng:-114.12380330669},{lat:51.799109509173,lng:-114.12273800578},{lat:51.799558197929,lng:-114.1223323167},{lat:51.799684004911,lng:-114.12232429316},{lat:51.799876802912,lng:-114.12248608283},{lat:51.800102904916,lng:-114.12290678386},{lat:51.800133809341,lng:-114.12306439938},{lat:51.800077007986,lng:-114.12331471639},{lat: 51.799693211411, lng: -114.12380330669}];
and the polygon is set as editable
When this event fires:
blockpolygon.addListener("rightclick", function(event)
{
this.getPath().removeAt(event.vertex);
}
The vertex from the first path on the list is removed, which is not the vertex that was "clicked"
Is there any way to remove the vertex from the correct path?
If I could identify which path and have the removeAT pointed to the correct path, that would make my day.

the hint from geocodezip was enough. Here's the solution:
blockpolygon.addListener("rightclick", function(event)
{
for (i=0; i<this.getPaths().getLength(); i++)
{
for (j=0; j< this.getPaths().getAt(i).getLength(); j++)
{
var distance = google.maps.geometry.spherical.computeDistanceBetween(event.latLng, this.getPaths().getAt(i).getAt(j));
if (distance==0) this.getPaths().getAt(i).removeAt(j);
}
}
}

Related

How to query exactly selected items in Paper.js?

According to my understanding, project.getItems({selected: true}) returns wrong results: I'm selecting a curve, it returns the parent Path: Sketch
Try clicking on a curve or a segment. Whole path will be moved. Then try changing the behavior by setting var workaround = false to var workaround = true to observe desired behavior.
How can I get exactly what is really selected?
Current workaround
I'm currently adding those objects into an array on selection and use those items instead of project.getItems({selected: true}).
The thing is that in Paper.js architecture, curves and segments are not items (they are part of a specific item which is the path). So you shouldn't expect project.getItems() to return anything else than items.
Another thing you have to know is that a path is assumed selected if any of its part is selected (curves, segments, points, handles, position, bounds, ...). And a curve is assumed selected if all of its parts are selected (points and handles).
With that in mind, you can create an algorithm to retrieve "what is really selected" based on project.getItems({selected: true}) as its first part. Then, you need to loop through curves and segments to check if they are selected.
Here is a sketch demonstrating a possible solution.
var vector = new Point(10, 10);
// Create path.
var path = new Path({
segments: [
[100, 100],
[200, 100],
[260, 170],
[360, 170],
[420, 250]
],
strokeColor: 'red',
strokeWidth: 10
});
// Translate given thing along global vector.
function translateThing(thing) {
switch (thing.getClassName()) {
case 'Path':
thing.position += vector;
break;
case 'Curve':
thing.segment1.point += vector;
thing.segment2.point += vector;
break;
case 'Segment':
thing.point += vector;
break;
}
}
// On mouse down...
function onMouseDown(event) {
// ...only select what was clicked.
path.selected = false;
hit = paper.project.hitTest(event.point);
if (hit && hit.location) {
hit.location.curve.selected = true;
}
else if (hit && hit.segment) {
hit.segment.selected = true;
}
// We check all items for demo purpose.
// Move all selected things.
// First get selected items in active layer...
project.activeLayer.getItems({ selected: true })
// ...then map them to what is really selected...
.map(getSelectedThing)
// ...then translate them.
.forEach(translateThing);
}
// This method returns what is really selected in a given item.
// Here we assume that only one thing can be selected at the same time.
// Returned thing can be either a Curve, a Segment or an Item.
function getSelectedThing(item) {
// Only check curves and segments if item is a path.
if (item.getClassName() === 'Path') {
// Check curves.
for (var i = 0, l = item.curves.length; i < l; i++) {
if (item.curves[i].selected) {
return item.curves[i];
}
}
// Check segments.
for (var i = 0, l = item.segments.length; i < l; i++) {
if (item.segments[i].selected) {
return item.segments[i];
}
}
}
// return item by default.
return item;
}
That said, depending on your real use case, your current workaround could be more appropriate than this approach.

GeoFire - Save item to specific location with radius

I don't have any code to share at this point, but I'm trying to figure out how to solve my issue.. I was hoping some of you might have some advice.
I'm building an app where I get the user's lat/long from geolocation and if they are in an predetermined area with a radius they can post data to the server, but not if they aren't in an area that I specified is allowed.. Here is an image for example:
So in this example, the user could post if they are in the radius of one of the circles but not if they aren't.
I would also have to fetch the data based off of which circle they are in..
What I'm wondering is, how would I specify where these radius' exist and does this scale easily? If I needed to add 10-30 new locations would that be easy to do?
You have the user location from the device and as you have the circles; you have the circle centre with their radius. At time of posting, you check the distance from the user location to the circle centre and enumerate thought the circle locations. if the distance is within the radius, they can post if not, not.
var radius = 100 //example
let canPostLocations = [
CLLocation1,
CLLocation2
]
func isInRange() -> Bool {
for canPost in canPostLocations {
let locationDistance = location.distance(from: canPost)
if (locationDistance < radius) {
return true
}
}
return false
}
use as:
var mayPost = false
var userLocation: CLLocation! = nil
if userLocation != nil {
mayPost = InRange(location: userLocation).isInRange()
}

Traversing based on multiple vertexes

I've a graph in OrientDB with vertexes Area & Place with edges visited. Your average path goes Area > visited > Place > visited > Place > visited > Place > visited > Place and so on. It tracks which places user visited after the previous one. visited contains YYYYmmDD datestamp.
I'm trying to find out all Area vertexes based on arbitrary Place vertexes for certain day - i.e. I want to know from which areas users came to a certain place after visiting certain place first.
Traversing from any single Place in the path would be easy but I need to to follow the path for only for a specific datestamp. What I did was that I created index for datestamp to get day's visited edges quickly and then finds the one that has in to the first Place. However now I can't figure out how to create a fast query that finds all Area vertexes based on the first Place while also making sure that the path contains second Place as well. I can get path between first and second Place via shortestPath() but I still have the same problem with extending the path to include Area vertexes.
I found some theory on the subject but if somebody could point me to the right direction how to use OrientDB to do this instead of pure graph theory I would really appreciate it - I've been working on this for the past week now. Originally this was done via bruteforce by traversing everything and then selecting but as the database grows it's not obviously sustainable.
I created the three Vertices 'Area', 'Place' and 'User' and the two Edges 'visited' and 'placed' where datestamp is a property on the edge 'visited.
In this way you don't have to insert everytime the User as a property on the edge.
Edit
Try this JavaScript function that has three parameters(places,date,propertyPlace)
var g=orient.getGraph();
var myPlaces=places.substring(1,places.length-1).split(",");
var b=g.command("sql","select from Area");
var result=[];
if(checkPlaces){
for(i=0;i<b.length;i++){
var listPlaces=[];
for(ind=0;ind<myPlaces.length;ind++){
listPlaces.push(myPlaces[ind]);
}
if(search(b[i],listPlaces)){
result.push(b[i]);
}
}
}
return result;
function checkPlaces() {
for(index=0;index<myPlaces.length;index++){
var place=g.command("sql","select from Place where "+ propertyPlace + "='"+myPlaces[index]+"'");
if(place.length==0){
return false;
}
}
return true;
}
function checkDate(edge){
var datestamp=edge.getRecord().field("datestamp");
var year=datestamp.getYear()+1900;
var month=datestamp.getMonth()+1;
var day=datestamp.getDate();
var app=date.split("-");
var myYear=parseInt(app[0]);
var myMonth=parseInt(app[1]);
var myDay=parseInt(app[2]);
if(year==myYear && month==myMonth && day==myDay){
return true;
}
return false;
}
function search(v,places){
var edge=v.getRecord().field("out_visited");
if(edge!=null){
var edgeIterator=edge.iterator();
while(edgeIterator.hasNext()){
var edge = edgeIterator.next();
if (checkDate(edge)) {
var v1 = edge.field("in");
if(v1!=null){
var name = v1.field(propertyPlace);
for(j=0;j<places.length;j++){
if(name==(places[j])) {
places.splice(j, 1);
break;
}
}
if(places.length==0){
return true;
}
else if(search(v1,places)){
return true;
}
}
}
}
}
return false;
}
Using the following command
select expand(result) from (select myFunction("[place1,place2]","2015-12-03","name") as result)
Let me know if it works
This is not a solution to this exact problem but instead a workaround I came up with. Inspired by Orientdb get last vertex from each path when Traversing by edge property
I changed to structure so that Area is now created per visitation instead of being static and it includes yyyymmdd timestamp also. Now I can use Area to start the query and use visited edges to get Place vertices only for a certain date.
Here's the query:
SELECT $path, $depth FROM (
TRAVERSE * FROM (
SELECT outE('visited') FROM (
SELECT EXPAND(rid) FROM INDEX:area.dt WHERE key = 20151205
)
) WHILE (#class = 'visited' AND dt = 20151205) OR #class = 'place')
WHERE #class = 'place' AND NOT (outE() contains (dt=20151205))
This returns correct paths with vertices and edges so you can verify it's only for a certain day. However note that Area is not contained in the path and I still need to figure out how to do that but if you want, you can just traverse the first visited edge backwards in the path and get it that way.

ArangoDB: traverse only edges within a time range

I am experimenting with time based versioning.
I have created a vertex that is connected to other vertices with this edge on one side:
{
"_id": "edges/426647569364",
"_key": "426647569364",
"_rev": "426647569364",
"_from": "nodes/426640688084",
"_to": "nodes/426629284820",
"valid_from": "1385787600000",
"valid_till": "9007199254740991"
}
And this edge on the other:
{
"_id": "edges/426679485396",
"_key": "426679485396",
"_rev": "426845488084",
"_from": "nodes/426675749844",
"_to": "nodes/426629284820",
"valid_from": "1322629200000",
"valid_till": "1417323600000"
}
The valid_till value in the first edge is the output of the Number.MAX_SAFE_INTEGER function.
I looked at custom vistors a little and it looks like its focused on filtering vertices rather than edges.
How can I restrict my traversal to edges with a valid_till value between new Date().getTime() and Number.MAX_SAFE_INTEGER?
You can use the followEdges attribute in a traversal.
followEdges can optionally be a JavaScript function for filtering edges. It will be invoked for each edge in the traversal:
var expandFilter = function (config, vertex, edge, path) {
return (edge.vaild_till >= new Date().getTime() &&
edge.valid_till <= Number.MAX_SAFE_INTEGER);
};
require("org/arangodb/aql/functions").register("my::expandFilter", expandFilter);
It can then be used in a traversal like a regular custom filter by specifying it in the followEdges attribute of the traversal options, e.g.:
LET options = {
followEdges: 'my::expandFilter'
}
FOR doc IN TRAVERSAL(nodes, edges, 'nodes/startNode', 'inbound', options)
RETURN doc.vertex

Draw Route X Kilometers from Origin

Running/walking distance display.
User enters a location and a distance.
I can overlay a circle with a radius of the distance the user entered, with the user's location as the center point.
I can set four cardinal points (N, S, E, W) around the point of origin at the distance the user set and draw the routes to those points, such that point B is 100KM from point A, but the mapped route is, say, 145km along the road.
Is it possible to display a route along the road exactly 100km?
Edited to update progress.
Finally solved this and thought I'd share.
so, the user supplies a location and a distance; we'll say 100Km.
The code finds cardinal points 100Km N, S, E, W of the point of origin, then solves routes to each point. If solving for the route is successful, the result contains an array of points from the point of origin to the destination.
directionsService.route({
origin: start,
destination: end,
travelMode: google.maps.DirectionsTravelMode.DRIVING
}, function(result) {
renderDirections(result);
});
//don't use the google api DirectionsRender() to draw the route.
//instead - result holds an array of lat/long points that make up the entire route. Lets say it's latlong[123]
//iterate through that array, getting a distance from point A to latlong[0], A to latlong[1], etc...
//when that distance is >= user supplied distance, STOP, and draw a polyline from point A through the latlong points in the array latlong[78]
function computeTotalDistance(result) {
var total = 0;
var myroute = result.routes[0];
if(myroute)
{
//create a LatLon from the Starting point
var objGeo = new LatLon(Geo.parseDMS(myroute.overview_path[0].Qa), Geo.parseDMS(myroute.overview_path[0].Ra));
//call get distance from the starting point to each other point in the array
//each subsequent point should be a longer distance
var arrPointsToDraw =[];
for(var i = 1; i<=myroute.overview_path.length-1;i++)
{
try
{
var objGeo2 = new LatLon(Geo.parseDMS(myroute.overview_path[i].Qa), Geo.parseDMS(myroute.overview_path[i].Ra));
}
catch(err)
{
alert(err.description);
}
//here, total = kilometers
total = objGeo.distanceTo(objGeo2,3);
//add coordinates to our array of points that we are going to draw
arrPointsToDraw.push(new google.maps.LatLng(objGeo2._lat, objGeo2._lon));
if(parseInt(total) > parseInt(distance.value))
{
arrPointsToDraw.pop();//remove the last element of the array
break;
}
}
//at this point, arrPointsToDraw[] contains the lat/long points that are closest to our distance
//without going over
lines[lines.length] = new google.maps.Polyline({
path: arrPointsToDraw,
strokeColor: '#1589FF',
strokeOpacity: 1.0,
strokeWeight: 3
});
lines[lines.length-1].setMap(map);
}//end if(myRoute)
}
This code makes use of two fantastic collections of functions found here

Resources