Anylogic - restrict agents from going into specific GIS region - anylogic

I'm currently working on a model where agents move to random points in the ocean on a GIS map. However, I want them to path in such a way that they do not collide with any islands on the map. I was thinking about creating GIS regions using the perimeter of the islands and was hoping there was some access restriction option for GIS regions. However, this does not seem to be a feature yet.
Does anyone have any tips on how to make agents avoid entering certain regions while moving towards a point on a GIS map? Thanks.

Create GISRoutes and move along those

One option is to generate the routes and then assess if they do overlap an island. If they do then you change that part of the route. See code example below, note I did not do all the math to create a new route that goes around the island... You believe you can do this yourself. It is going to be a piece of work, so I did not test this or develop the completed solution.
GISRoute route = main.map.getRoute(currentLat, currentLong, toLat, toLong);
List<GISMarkupSegment> segementsToKeep = new ArrayList<GISMarkupSegment>()
SegmentForLoop:
for (int i = 0; i < route.getSegmentCount(); i++) {
GISMarkupSegment segment = route.getSegment(i);
// Check if the segmeent is too close to an island, if within 100m then we adjust the segment and stop adding segeents
for (Pair<Double, Double> pair:main.LatLongPointsOIfIslands) {
double distance = Math.sqrt(segment.getDistanceSq(new Point(pair.getFirst(), pair.getSecond())));
if (distance < 100) {
segment.setEnd(pair.getFirst() + 100, pair.getSecond()+100);
break SegmentForLoop:
}
segementsToKeep.add(segment);
}
}
GISRoute routeUpToIsland = new GISRoute(main, segementsToKeep);
//TODO
// Create a new route around the island
// Add the segements of this new route to segementsToKeep
LatLongPointsOIfIslands is a collection of Pair<Double,Double> which is just lat and long combinations of all the GIS points of the island perimeters
I hope this helps or puts you on the right direction.
Alterantively you can investigate alternative routing providers

Related

Anylogic - line of sight

Is there a way to check if there is a line of sight between two agents assuming some buildings and presentation markup?
(Meaning a function that would check if two agents can see each other assuming buildings and walls)
This is how I did it once in the past. The only problem is that it might be slow if you need to do that calculation thousands of times per second. And it's only in 2D. If you need 3D, the idea is not so different.
1) add all your building nodes and everything that might be an obstacle between the two agents to a collection. You may want to put a rectangular node around your buildings to keep everything in one collection (assuming you are using space markup with nodes)
2) generate a delta distance delta (equal to 1 for example) and find the angle of the line that passes through both agents.
3) Make a loop from the position of agent1 till the position of agent2. It will be something like this:
L=delta;
while(L<LThatReachesSecondAgent){
x1 = agent1.getX() + L*cos(angle);
y1 = agent1.getY() + L*sin(angle);
for(Node n : yourCollectionOfNodes){
If(n.contains(x1,y1))
return false
}
/*This can also work maybe faster
//int numNodesInTheWay=count(yourCollectionOfNodes,n->n.contains(x1,y1));
//if(numNodesInTheWay>0) return false
*/
L+=delta;
}
return true
welcome to SOF.
No, there is no build-in function, afaik. You would have to code something manually, which is possible but not straight forward. If you want help with that, you need to provide more details on the specifics.

Mapbox: How are tiles sizes and positions calculated

I'm trying to get through the learning curve of not just the mapbox api but how map applications work in general. Currently I'm having difficulty understanding the calculation used in sizing and placing tiles based on LngLat and Zoom level.
I checked out the Slippy maps wiki but it does not seem to align with how mapbox works (or more likely my understanding is incorrect).
I'm hoping someone can point me to a resource that can clearly explain the calculations for the mapbox-gl api tile placement.
Thanks!
More Specifically: I'm trying to figure out how to cover a tile with a 3D plane using threebox. To do this I need to:
get the tile's size (which changes depending on zoom level)
get the tile's position (which I can get using bbox, however I don't think my calculations are correct because at zoom level 2 the 3D plane's latitude is off by 40.97 degrees when placed using threebox)
My calculation for placing the tiles:
var offset = 40.97// temporarily used to fix placement.
var loc_x = bounds[0] + ((bounds[2] - bounds[0])/2); // this works as expected
var loc_y = bounds[1] + offset;
var loc_z = 0;
if (bounds[1] < 0) {
loc_y = bounds[3] - offset;
}
Found the reason I needed the offset property. The 3D plane's registration (0,0 coords) needed to match the tile. By default the 3D plane's registration point was in the center of the mesh, rather than the bottom left.

Leaflet - tooltips for overlapping polylines

Background:
I am working on a web based mapping application for hiking. So the map based on leaflet offers routes on hiking trails that are labeled. As any hiking trail can be part of multiple routes, routes - respectively the corresponding polylines representing the routes - can overlap.
Problem:
Each route has its tooltip (triggered by mouseover, {sticky:true}) showing its label which works as expected for non-overlapping polylines but as soon as two or more routes overlap only the polyline "on top" gets its tooltip opened. This behaviour is not bad per se but as all routes are equally important I would like to show all labels of the routes at the pointer's location (or something like a maximum of 5 labels + x more). I weren't able to find any issue related to this topic.
What I tried:
- Create a feature group for all routes, bind the tooltip to the group, hoping that the tooltip function provides an array of all polylines crossing the pointer's position. As it turned out, I only get information of the polyline on top
- I tried the same with a mousemove event on the map, no success
- Comparing pointer's layerPoint coordinates with all routes' _rings & _parts layPoint arrays to find matching layerPoints, but the success rate is only about 5% as these layerPoints only cover actual points of the polyline but not the connection between two points. Additionally, there is a margin around each polyline that triggers the tolltip before the pointer even touches the polyline (too improve touch action, I guess)
- A solution to the margin problem is to add positive and negative margins to each polyline point before comparing it to the pointer coordinates which improves the outcome but doesn't solve the main problem.
Sidenote:
- All routes are drawn into a single canvas
Long story short, I need external help to accomplish the goal. Maybe some of you have an idea or can provide a solution. Any input is appreciated.
** UPDATE: **
A working but pretty inefficient solution is as follows
Approach:
Calculate the shortest distance from the pointer to all routes in viewport. If distance from the pointer to a route is under a certain threshold, add them to the array of route labels that should be displayed.
Steps:
1.) bind a blank tooltip to the a feature group containing all routes
2.) bind mousemove event to the feature group with the follwing function
var routesFeatureGroup = L.featureGroup(routesGroup)
.bindTooltip('', {sticky: true})
.on('mousemove', function(e){
var routeLabels = [e.layer.options.label]; // add triggering route's label by default
var mouseCoordAbs = el.$map.project(e.latlng);
$.each(vars.objectsInViewport.routes, function(i, v){
if (e.layer.options.id != el.$routes[i].options.id && el.$routes[i]._pxBounds.contains(e.layerPoint)){
var nearestLatlngOnPolyline = getNearestPolylinePoint(e.latlng, el.$routes[i]);
var polyPointCoordAbs = el.$map.project(nearestLatlngOnPolyline);
var distToMouseX = polyPointCoordAbs.x - mouseCoordAbs.x;
var distToMouseY = polyPointCoordAbs.y - mouseCoordAbs.y;
var distToMouse = Math.sqrt(distToMouseX*distToMouseX + distToMouseY*distToMouseY);
if (distToMouse < 15) {
routeLabels.push(el.$routes[i].options.label);
}
}
})
var routesFeatureGroup.setTooltipContent(routeLabels.join('<br>'));
})
Explanation:
I already gather all objects (routes and markers) in the current viewport for another part of the app. All routes currently visible are stored in vars.objectsInViewport.routes (respectively their ids), so I dont have to go through all routes. The layer that triggered the mousemove event is added by default. I then check for each of the routes currently visible if:
- their id is different to the layer that trigger the mousemove event (as this label is added by default)
- if their bounds (in cartesian coordinates: "_pxBounds") contain the cartesian layerPoint of the mousemove event (for a rough approch to exclude routes that don't intersect)
If these conditions are met for a route, calculate the closest latlng point from the pointer to the route. I do this with a custom function, which is a bit to long to post it in this context. (I will if someone asks for it)
The mouse position and the latlng point on the polyline / route are then converted to absolute coordinates using the map-project method
http://leafletjs.com/reference.html#map-project
At last, the distance between these to points is calculated using pythagoras. It is pixel based, so that the zoom level isn't a factor. If the distance is below a certain threshold (15px) they are close enough to the pointer to be considered as being hovered (with the default margins around a polyline), so the label of the route is added to the label array.
Finally the tooltip for the feature group is filled with all labels.
Results are pretty promising even though the operation is pretty expensive. I added a timeout of 50ms to reduce the function call a bit:
var tooltipTimeout;
var routesFeatureGroup = L.featureGroup(routesGroup)
.bindTooltip('', {sticky: true})
.on('mousemove', function(e){
clearTimeout(tooltipTimeout);
tooltipTimeout = setTimeout(function(){
// collect labels
// ...
},50);
.on('mouseout', function(){
clearTimeout(tooltipTimeout);
})
I can give you an idea of how to do this, but I am not 100% sure that it will do the job. There is a plugin for Leaflet (Mapbox) that can tell you if a point is within a Polygon and it returns all the Polygons that contain that point.
If this plugin doesn't work for polylines you can create a polygon from a polyline by just going back from the last point to the first and closing the line (I am not sure if this suits you solution). For example if you have a polyline of connected points of [0, 1, 2, .... n-1, n] you then go back with connecting [n with n-1, n-1 with n-2, ... 1 with 0]. This way you will have the same shape of the polyline but it will be a polygon. This isn't the most optimized solution, it is a quick fix that uses a known and available plugin.
Once you get all the tooltips, you can open all of them at once for each polygon/polyline. Or maybe open some helper tooltip where the user can select which one he wants to open.
I hope this helps! If you figure out a better solution (or find a plugin that does the job) please post it here.

Displaying a Mesh based on pointcloud data

I am sampling data from the point cloud and trying to display the selected points using a mesh renderer.
I have the data but I can't visualize it. I am using the Augmented Reality application as template.
I am doing the point saving and mesh population in a coroutine. There are no errors but I can't see any resulting mesh.
I am wondering if there is a conflict with an existing mesh component from the point cloud example that I use for creating the cloud.
I pick a point on screen (touch) and use the index to find coordinates and populate a Vector3[]. The mesh receiveds the vertices( 5000 points out of 500000 in the point cloud)
this is where I set the mesh:
if (m_updateSubPointsMesh)
{
int[] indices = new int[ctr];
for (int i = 0; i < ctr; ++i)
{
indices[i] = i;
}
m_submesh.Clear();
m_submesh.vertices = m_subpoints;
int vertsInMesh = m_submesh.vertexCount;
m_submesh.SetIndices(indices, MeshTopology.Points, 0);
}
m_subrenderer.material.SetColor("_SpecColor", Color.yellow);
I am using Unity pro 5.3.3 and VS 2015 on windows 10.
Comments and advice are very much appreciated even if they are not themselves a solution.
Jose
I sort it out. The meshing was right it turn out to be a bug on a transform (not tango-defined). The mesh was rendered in another point. Had to walk around to find it.
Thanks
You must convert the Tango mesh data to mesh data for unity, its not structured in the same way I believe its the triangles thats different. You also need to set triangles and normals to the mesh.

Relative coordinate calculation in custom map

I'm currently working on a mapping app for iPhone. I've created some custom maps of various sizes, but I've run into an issue:
I would like to implement the ability for users' locations to be checked automatically, but since Im not using a MapView this is much more dificult. (see below)
given the different coordinate systems, I would like to receive a geolocation (green dot) and translate it into a pixel location on a custom map.
Ive got the geolocations for the 4 corners, but the rect is askew. Ive calculated the angle of rotation, but Im just generally confused.
note: the size of the maps arent big enough for the spherical nature of the earth to come into calculation.
Any help is appreciated!
To convert a geolocation to point you need to first understand the mapping. assuming you are using Mercator.
x = R*long
y = R*(1+sin(lat))/cos(lat)
where lat and long are in radians.R is radius of earth. the scale of the image would be from 0 to R*PI
so to get it within view.frame.size you may have to divide by a scale factor.
for difference between points.
x2-x1 = R* (long2-long1)
y2-y1 = R* ( (1+sin(lat2))/cos(lat2) - (1+sin(lat1))/cos(lat1) )