Flutter polyline distance with google_maps_flutter plugin - flutter

Hi I am using the google_maps_flutter plug in and have gotten a polyline to show up on my map. What I would like to do is calculate the distance of the polyline length. My code is linked here and there is a snippet below. I do not want to use the Directions API. How do I calculate polyline distance and print to console? Thanks for reading.
class ShowMap extends StatefulWidget {
final double lat;
final double lng;
ShowMap({Key key, this.lat, this.lng}) : super(key: key);
#override
_ShowMapState createState() => _ShowMapState();
}
class _ShowMapState extends State<ShowMap> {
// Field
double lat, lng;
BitmapDescriptor policeIcon;
List<Marker> list = List();
List<String> listDocuments = List();
final Set<Polyline> _polyline = {};
GoogleMapController controller;
List<LatLng> latlngSegment1 = List();
List<LatLng> latlngSegment2 = List();
static LatLng _lat1 = LatLng(45.19, -121.59);
static LatLng _lat2 = LatLng(45.30, -122.20);
static LatLng _lat3 = LatLng(45.11, -122.61);
static LatLng _lat4 = LatLng(45.42, -122.62);
static LatLng _lat5 = LatLng(45.34, -122.32);
static LatLng _lat6 = LatLng(45.21, -122.2);
bool _myLocationButtonEnabled = true;
bool _myLocationEnabled = true;
// Method
#override
void initState() {
super.initState();
// findLatLng();
readDataFromFirebase();
setState(() {
lat = widget.lat;
lng = widget.lng;
latlngSegment1.add(_lat1);
latlngSegment1.add(_lat2);
latlngSegment1.add(_lat3);
latlngSegment1.add(_lat4);
//line segment 2
latlngSegment2.add(_lat4);
latlngSegment2.add(_lat5);
latlngSegment2.add(_lat6);
latlngSegment2.add(_lat1);
});
}

Let us say that you want to calculate the distance of polyline created by the points in latlngSegment1.
For that you need to calculate the distance between each consecutive LatLng points in latlngSegment1.
I would do it with something like this.
double calculateDistane(List<LatLng> polyline) {
double totalDistance = 0;
for (int i = 0; i < polyline.length; i++) {
if (i < polyline.length - 1) { // skip the last index
totalDistance += getStraightLineDistance(
polyline[i + 1].latitude,
polyline[i + 1].longitude,
polyline[i].latitude,
polyline[i].longitude);
}
}
return totalDistance;
}
double getStraightLineDistance(lat1, lon1, lat2, lon2) {
var R = 6371; // Radius of the earth in km
var dLat = deg2rad(lat2 - lat1);
var dLon = deg2rad(lon2 - lon1);
var a = math.sin(dLat / 2) * math.sin(dLat / 2) +
math.cos(deg2rad(lat1)) *
math.cos(deg2rad(lat2)) *
math.sin(dLon / 2) *
math.sin(dLon / 2);
var c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a));
var d = R * c; // Distance in km
return d * 1000; //in m
}
dynamic deg2rad(deg) {
return deg * (math.pi / 180);
}
Note: The getStraightLineDistance() function gives the straight line distance between two latlng points, which might not be the way someone reaches from point A to B.

Related

how to let SpriteAnimationComponent follow BodyComponent

how to let SpriteAnimationComponent follow BodyComponent, which can fall due to gravity. currently SpriteAnimationComponent still keep in the air, here is my code:
class Chick extends BodyComponent {
Vector2 fallPosition;
SpriteAnimationComponent chick = SpriteAnimationComponent();
Chick({
this.fallPosition,
});
final spriteSize = Vector2(32, 34) / 2;
#override
Future<void> onLoad() async {
await super.onLoad();
var spriteData = SpriteAnimationData.sequenced(
amount: 14, stepTime: 0.1, textureSize: Vector2(32, 34));
chick = SpriteAnimationComponent.fromFrameData(
spriteSize, ImageTool.image('chicken.png'), spriteData)
..x = fallPosition.x
..y = fallPosition.y
..anchor = Anchor.center
..size = spriteSize;
await addChild(chick);
}
#override
void update(double dt) {
chick.position = body.position;
print('body.position ! ${body.position} == $fallPosition}');
super.update(dt);
}
#override
Body createBody() {
debugMode = true;
final shape = CircleShape()..radius = spriteSize.x / 2;
var position = fallPosition.clone();
var worldPosition = viewport.getScreenToWorld(position);
final fixtureDef = FixtureDef()
..shape = shape
..restitution = 0.1
..density = 0.1
..friction = 0.1;
final bodyDef = BodyDef()
..userData = this
..angularDamping = 0.1
..position = worldPosition
..type = BodyType.DYNAMIC;
return world.createBody(bodyDef)..createFixture(fixtureDef);
}
}
I realize fallPosition, fallPosition, and chick.position has different value, but I dont know how to make this SpriteAnimationComponent follow Body, thanks for any help!
Add the SpriteBodyComponent as a child to the BodyComponent by simply running add, and remove the attempts that you have at synchronizing the positions, this will be done automatically once you have added it as a child.
To do this you also need to upgrade to a newer version of Flame (preferably v1.4.0 or newer) and a new version of flame_forge2d (> 0.12.3). Do note that addChild has been renamed to add.

PolygonShape created at different position

I'm trying to create a polygon at the center of the screen with a mouse joint, very simple.
A CircleShape works great. Also the mouse joint behaves strangely and I couldn't find a pattern.
All code is in the main file here. I kept the code to a minimum.
Vector2 vec2Median(List<Vector2> vecs) {
var sum = Vector2(0, 0);
for (final v in vecs) {
sum += v;
}
return sum / vecs.length.toDouble();
}
void main() {
final game = MyGame();
runApp(GameWidget(game: game));
}
class MyGame extends Forge2DGame with MultiTouchDragDetector, HasTappables {
MouseJoint? mouseJoint;
static late BodyComponent grabbedBody;
late Body groundBody;
MyGame() : super(gravity: Vector2(0, -10.0));
#override
Future<void> onLoad() async {
final boundaries = createBoundaries(this); //Adding boundries
boundaries.forEach(add);
groundBody = world.createBody(BodyDef());
final center = screenToWorld(camera.viewport.effectiveSize / 2);
final poly = Polygon([
center + Vector2(0, 0),
center + Vector2(0, 5),
center + Vector2(5, 0),
center + Vector2(5, 5)
], bodyType: BodyType.dynamic);
add(poly);
grabbedBody = poly;
}
#override
bool onDragUpdate(int pointerId, DragUpdateInfo details) {
final mouseJointDef = MouseJointDef()
..maxForce = 3000 * grabbedBody.body.mass * 10 //Not neccerly needed
..dampingRatio = 1
..frequencyHz = 5
..target.setFrom(grabbedBody.body.position)
..collideConnected = false //Maybe set to true
..bodyA = groundBody
..bodyB = grabbedBody.body;
mouseJoint ??= world.createJoint(mouseJointDef) as MouseJoint;
mouseJoint?.setTarget(details.eventPosition.game);
return false;
}
#override
bool onDragEnd(int pointerId, DragEndInfo details) {
if (mouseJoint == null) {
return true;
}
world.destroyJoint(mouseJoint!);
mouseJoint = null;
return false;
}
}
abstract class TappableBodyComponent extends BodyComponent with Tappable {
final Vector2 position;
final BodyType bodyType;
TappableBodyComponent(this.position, {this.bodyType = BodyType.dynamic});
#override
bool onTapDown(_) {
MyGame.grabbedBody = this;
return false;
}
Body tappableBCreateBody(Shape shape) {
final fixtureDef = FixtureDef(shape)
..restitution = 0.8
..density = 1.0
..friction = 0.4;
final bodyDef = BodyDef()
// To be able to determine object in collision
..userData = this
..angularDamping = 0.8
..position = position
..type = bodyType;
return world.createBody(bodyDef)..createFixture(fixtureDef);
}
}
class Polygon extends TappableBodyComponent {
final List<Vector2> vertecies;
Polygon(this.vertecies, {BodyType bodyType = BodyType.dynamic})
: super(vec2Median(vertecies), bodyType: bodyType);
#override
Body createBody() {
final shape = PolygonShape()..set(vertecies);
return tappableBCreateBody(shape);
}
}
tappableBCreateBody encapsulate Tappable and body creation methods, Polygon is the object I'm trying to create, vec2Median returns the center of the polygon (by vertices).
Thank you very much!
I think that you have to remove center from the vertices and only add that as the position of the BodyComponent instead, like you already do in the super call of your Polygon class.

How to get direction from onDragUpdate

How would you get a direction from onDragUpdate?
Vector2 dragDeltaPosition = Vector2(0, 0);
Vector2 dragDirectionVector = Vector2(0, 0);
#override
bool onDragStart(DragStartInfo info) {
dragDeltaPosition = info.eventPosition.game - position;
return false;
}
#override
bool onDragUpdate(DragUpdateInfo info) {
// double x = info.eventPosition.game.x - dragDeltaPosition.x;
// double y = info.eventPosition.game.y - dragDeltaPosition.y;
// double x = info.eventPosition.game.x - info.delta.game.x;
// double y = info.eventPosition.game.y - info.delta.game.y;
dragDirectionVector = Vector2(x, y);
}
Update: this kind of work:
double x = (info.eventPosition.game - position).x - dragDeltaPosition.x;
double y = (info.eventPosition.game - position).y - dragDeltaPosition.y;
Let me know if there is a better way. Thanks
You'll have to look on the delta, which is the vector from the last onDragUpdate to the current one.
#override
bool onDragUpdate(DragUpdateInfo info) {
// You can use info.delta.game.normalized here too if you don't care
// about the length of the directional vector.
dragDirectionVector = info.delta.game;
}

How to return distances below 10km way flutter

Managed to sort my snapshots by those nearest to the user's location, but am having trouble showing only those that are within a returned distance of 10(km). I tried writing if statements above return totalDistance in the distance function, but no luck. Any help would be appreciated!
double calculateDistance(lat1, lon1, lat2, lon2){
var p = 0.017453292519943295;
var c = cos;
var a = 0.5 - c((lat2 - lat1) * p)/2 +
c(lat1 * p) * c(lat2 * p) *
(1 - c((lon2 - lon1) * p))/2;
return 12742 * asin(sqrt(a));
}
double distance(Position position, DocumentSnapshot snapshot){
final double myPositionLat = position.latitude;
final double myPositionLong = position.longitude;
final double lat = snapshot.data['latitude'];
final double long = snapshot.data['longitude'];
double totalDistance = calculateDistance(myPositionLat, myPositionLong, lat, long);
return totalDistance;
}
#override
void initState() {
super.initState();
subscription = collectionReference.snapshots().listen((data) async {
final location = await getLocation();
print('user location = $location');
final documents = data.documents;
documents.sort((a, b) {
final distanceA = distance(location, a);
final distanceB = distance(location, b);
return distanceA.compareTo(distanceB);
});
}
Try using where to filter the list. I've never used Dart but I imagine it looks something like this:
final documents = data.documents.where((a) => distance(location, a) < 10);
Maybe tack on .toList(); if you want an actual List and not an Iterable.

java.lang.ClassCastException: [Ljava.lang.Object; error in drawing path from Double[]name?

i am having this error java.lang.ClassCastException: [Ljava.lang.Object; in drawing a route from list of point
here is my drawing code
public class MyOverlay extends Overlay{
List<Double> location;
List<Double> lt;
List<Double> ln;
MapView mapView ;
Double[]lat;
Double[]lon;
public MyOverlay(List<Double> location, List<Double> lt, List<Double> ln, MapView mapView) {
// TODO Auto-generated constructor stub
this.location = location;
this.mapView = mapView;
this.ln =ln;
this.lt = lt;
}
#Override
public void draw(android.graphics.Canvas canvas, MapView mapView, boolean shadow) {
super.draw(canvas, mapView, false);
lat = (Double[])lt.toArray();
lon = (Double[]) ln.toArray();
Path path1 = new Path();
Point p1 = new Point();
Path path2 = new Path();
Point p2 = new Point();
Point p3 = new Point();
Point p4 = new Point();
Projection projection = mapView.getProjection();
int a = lat.length;
int b = lon.length;
int sum = a+b;
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5);
paint.setAlpha(90);
Path p = new Path();
Point from = new Point();
Point to = new Point();
for (int i = 1; i < sum; i++)
{
if (i == sum - 1)
{
break;
}
GeoPoint point1 = new GeoPoint((int)(lat[i]*1E6) , (int)(lon[i]*1E6));
(int)(Double.valueOf(lon[i+1])*1E6));
projection.toPixels( point1, from);
//projection.toPixels(point2, to);
if(i ==1)
{
p.moveTo(from.x, from.y);
}
else
{
p.lineTo(to.x, to.y);
}
canvas.drawPath(p, paint);
}
}
tell me what i am doing wrong?
List.toArray() returns an array of Objects: Object[]. And an Object[] can't be cast to a Double[].
You should use
lat = lt.toArray(new Double[lt.size()]);
which returns a Double[]. See the javadoc.