Sup, guys! I have a task to calculate coordinates of continuation line between points A & B. I have a code each calculate distance between these points, and I have tangent of angle for calculating next points D and F. Thanks for any help
`val pointA = LatLng(a.latitude, a.longitude)
val pointB = LatLng(b.latitude, b.longitude)
val pointC = LatLng(a.latitude, b.longitude)//for calculating
val polylineOptions = PolylineOptions()
.add(pointA)
.add(pointB)
.add(pointC)
.add(pointA)
val distanceAB = getKmFromLatLong(pointA.latitude, pointA.longitude, pointB.latitude, pointB.longitude)
val distanceBC = getKmFromLatLong(pointB.latitude, pointB.longitude, pointC.latitude, pointC.longitude)
val distanceCA = getKmFromLatLong(pointC.latitude, pointC.longitude, pointA.latitude, pointA.longitude)
val tang = distanceBC/distanceCA
println("__ distanceAB $distanceAB")
println("__ distanceBC $distanceBC")
println("__ distanceCA $distanceCA")
println("__ tang $tang")`
Thanks, guys! Point-slope formula - rules
private fun generateNeedingPoints(a: LatLng, b: LatLng): List<LatLng> {
setScreenBounds()
val c: LatLng
val d: LatLng
val longitudeC = if (a.longitude < b.longitude) northEast.longitude else southWest.longitude
val longitudeD = if (a.longitude < b.longitude) southWest.longitude else northEast.longitude
c = calculateEdgeButton(a, b, longitudeC)
d = calculateEdgeButton(b, a, longitudeD)
return mutableListOf(d, a, b, c)
}
`
private fun calculateEdgeButton(a: LatLng, b: LatLng, edgeLng: Double, distortionCoefficient:Double = 1.0): LatLng{
val longChange = b.longitude - a.longitude
val latChange = b.latitude - a.latitude
val slope = latChange / longChange
val longChangePointC = edgeLng - b.longitude
val latChangePointC = longChangePointC * slope
val latitudeC = b.latitude + latChangePointC
return LatLng(latitudeC * distortionCoefficient, edgeLng)
}
`
Related
I am developing an application to show ECG waveform in an android application. I tried using MPAndroidchart and XYPlotlibrary to plot the ECG data. I can able to see Major grid lines, but my requirement is to show both Major and minor gridlines So that it will resemble Ecg graph paper. Can anyone have any suggestion or suggest any library to achieve this functionality?
It's not possible to draw minor grid lines using a built-in chart capability with MPAndroidChart, but you can still add them manually to get the desired appearance.
For example:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val chart = findViewById<LineChart>(R.id.chart)
val lines = mutableListOf<LineDataSet>()
val x = (0..100).map { i -> 0.1f*i }
val y = x.map { i -> 5*sin(7*i)*sin(0.5f*i)* cos(3.25f*i) }
val primaryLine = LineDataSet(x.zip(y).map { Entry(it.first, it.second) }, "primary")
primaryLine.setDrawCircles(false)
primaryLine.lineWidth = 3f
primaryLine.color = Color.RED
primaryLine.setDrawValues(false)
primaryLine.isHighlightEnabled = false
val majorX = 2f
val majorY = 4f
val minorX = majorX/5
val minorY = majorY/5
val xmin = floor(x.min()/majorX)*majorX
val xmax = ceil(x.max()/majorX)*majorX
val ymin = floor(y.min()/majorY)*majorY
val ymax = ceil(y.max()/majorY)*majorY
xGridLines(lines, minorX, ymin, ymax, xmin, xmax, false)
yGridLines(lines, minorY, ymin, ymax, xmin, xmax, false)
xGridLines(lines, majorX, ymin, ymax, xmin, xmax, true)
yGridLines(lines, majorY, ymin, ymax, xmin, xmax, true)
lines.add(primaryLine)
chart.axisRight.isEnabled = false
val yAx = chart.axisLeft
yAx.setDrawLabels(false)
yAx.setDrawGridLines(false)
yAx.setDrawAxisLine(false)
yAx.axisMinimum = ymin
yAx.axisMaximum = ymax
val xAx = chart.xAxis
xAx.setDrawLabels(false)
xAx.position = XAxis.XAxisPosition.BOTTOM
xAx.setDrawGridLines(false)
xAx.setDrawAxisLine(false)
xAx.axisMinimum = xmin
xAx.axisMaximum = xmax+0.01f
chart.data = LineData(lines.toList())
chart.description.isEnabled = false
chart.legend.isEnabled = false
}
private fun yGridLines(lines: MutableList<LineDataSet>, spacing: Float, ymin: Float, ymax: Float, xmin: Float, xmax: Float, major: Boolean) {
val nY = ((ymax-ymin)/spacing).roundToInt()
for(i in 0..nY) {
val yl = ymin + i*spacing
val ep = listOf(Entry(xmin,yl), Entry(xmax,yl))
lines.add(makeGridLineDataSet(ep, major))
}
}
private fun xGridLines(lines: MutableList<LineDataSet>, spacing: Float, ymin: Float, ymax: Float, xmin: Float, xmax: Float, major: Boolean) {
val nX = ((xmax-xmin)/spacing).roundToInt()
for(i in 0..nX) {
val xl = xmin + i*spacing
val ep = listOf(Entry(xl, ymin), Entry(xl,ymax))
lines.add(makeGridLineDataSet(ep, major))
}
}
private fun makeGridLineDataSet(e: List<Entry>, major: Boolean): LineDataSet {
val ds = LineDataSet(e,"")
ds.setDrawCircles(false)
if( major ) {
ds.color = Color.BLACK
ds.lineWidth = 1f
}
else {
ds.color = Color.BLACK
ds.lineWidth = 0.5f
ds.enableDashedLine(10f,10f,0f)
}
ds.setDrawValues(false)
ds.isHighlightEnabled = false
return ds
}
Which produces
I have created an application that, given two input points, calls a function that draws a path, on a map, between the two points. I would now like to be able to implement the ability to click on the path and save it locally, in a list, so that I can retrieve it when necessary.
I'm a beginner with programming in kotlin and android, could you advise me how to do it?
I share below the function that I use to create the path in case it is useful.
fun routePath(p1Latit: Double, p1Laong: Double, p2Latit: Double, p2Laong: Double){
val roadManager: RoadManager = OSRMRoadManager(context, "lolloMaps")
OSRMRoadManager.MEAN_BY_FOOT
val waypoints = arrayListOf<GeoPoint>()
val startPoint: GeoPoint = GeoPoint(p1Latit, p1Laong)
waypoints.add(startPoint)
val endPoint: GeoPoint = GeoPoint(p2Latit, p2Laong)
waypoints.add(endPoint)
mapView.overlays.forEach{
if (it is Polyline && it.id == "Path"){
mapView.overlays.remove(it)
}
}
road = roadManager.getRoad(waypoints)
if (road.mStatus != Road.STATUS_OK){
Toast.makeText(context, "Error - status = " + road.mStatus, Toast.LENGTH_SHORT).show()
}
val roadOverlay: Polyline = RoadManager.buildRoadOverlay(road)
roadOverlay.id = "Path"
mapView.overlays.add(roadOverlay)
mapView.invalidate()
val nodeIcon: Drawable? = ResourcesCompat.getDrawable(mapView.resources, R.drawable.marker_node, null)
mapView.overlays.forEach{
if (it is Marker && it.id == "Node"){
mapView.overlays.remove(it)
}
}
for (i: Int in road.mNodes.indices){
val node: RoadNode = road.mNodes[i]
val nodeMarker: Marker = Marker(mapView)
nodeMarker.position = node.mLocation
nodeMarker.icon = nodeIcon
nodeMarker.title = "Passo $i"
nodeMarker.id = "Node"
mapView.overlays.add(nodeMarker)
nodeMarker.snippet = node.mInstructions
nodeMarker.subDescription = Road.getLengthDurationText(context,node.mLength, node.mDuration)
// var icon: Drawable = resources.getDrawable(R.drawable.ic_continue)
// nodeMarker.image = icon
}
}
abstract class MainActivity : AppCompatActivity(), Parcelable {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main))
val a = findViewById<TextView>(R.id.editTextNumberDecimal)
val b = findViewById<TextView>(R.id.editTextNumberDecimal2)
val c = findViewById<TextView>(R.id.editTextNumberDecimal3)
val e = findViewById<TextView>(R.id.editTextNumberDecimal4)
val f = findViewById<TextView>(R.id.editTextNumberDecimal5)
val g = findViewById<TextView>(R.id.editTextNumberDecimal6)
val n = findViewById<TextView>(R.id.editTextNumberDecimal13)
val h = findViewById<EditText>(R.id.editTextNumberDecimal7)
val i = findViewById<EditText>(R.id.editTextNumberDecimal8)
val j = findViewById<EditText>(R.id.editTextNumberDecimal9)
val k = findViewById<EditText>(R.id.editTextNumberDecimal10)
val l = findViewById<EditText>(R.id.editTextNumberDecimal11)
val m = findViewById<EditText>(R.id.editTextNumberDecimal12)
val o = findViewById<EditText>(R.id.editTextNumberDecimal14)
val bt = findViewById<Button>(R.id.button)
bt.setOnClickListener {
val fm = a.text.toString().toFloat()
val s = b.text.toString().toFloat()
val kmod1 = c.text.toString().toFloat()
val kmod2 = e.text.toString().toFloat()
val d1 = f.text.toString().toFloat()
val t = g.text.toString().toFloat()
val n1 = n.text.toString().toFloat()
val fk = (fm - (1.645 * s)).toFloat()
val ftk = 1.3 * fk
val fvk = 0.15 * fk
val fck = 0.1 * fk
val fmk = 1.1 * fk
val kmod = (kmod1 * kmod2 * 0.8).toFloat()
val fcd: Float = kmod * fk / 2
h.setText(fcd.toString())
val ftd = (kmod * ftk / 1.8).toFloat()
i.setText(ftd.toString())
val fvd = (kmod * fvk / 2).toFloat()
j.setText(fvd.toString())
val fcd1 = (kmod * fck / 2).toFloat()
k.setText(fcd1.toString())
val fmd = (kmod * fmk / 1.8).toFloat()
l.setText(fmd.toString())
val d = d1 - 2 * t
when I build the app it says that is Build Sucessfully but when I try to run it on the emulator, It keeps stopping.
the app is the calculator type It read some numbers as strings, turn them into floats numbers for it calculate and it writes the resulte as string again
I'm using Google Places api in my app which calculate the distance between 2 address,
the problem is that I get less distance than in google maps.
I cannot get the same accuracy as Google maps,
Most of the time distance is shorter than the result from Google Maps
private fun SetupPlacesAutocompleteFun() {
val _autocompletFragment1 = supportFragmentManager
.findFragmentById(R.id.fragmentPlaces1) as AutocompleteSupportFragment
_autocompletFragment1.setPlaceFields(_placesFields)
_autocompletFragment1.setOnPlaceSelectedListener(object:PlaceSelectionListener{
override fun onPlaceSelected(p1: Place) {
_adrees1 = p1.latLng!!
_adressString1 = p1.address!!
}
override fun onError(p1: Status) {
Toast.makeText(this#GooglePlaces_Activity,"status "+p1.statusMessage,Toast.LENGTH_LONG).show()
}
})
val _autocompletFragment2 = supportFragmentManager
.findFragmentById(R.id.fragmentPlaces2) as AutocompleteSupportFragment
_autocompletFragment2.setPlaceFields(_placesFields)
_autocompletFragment2.setOnPlaceSelectedListener(object :PlaceSelectionListener{
override fun onPlaceSelected(p2: Place) {
_adress2 =p2.latLng!!
_adressString2 = p2.address!!
}
override fun onError(p2: Status) {
Toast.makeText(this#GooglePlaces_Activity,"status "+p2.statusMessage,Toast.LENGTH_LONG).show()
}
})
}
private fun InitPlacesFun() {
Places.initialize(this,getString(R.string.Places_api))
_placcesClint = Places.createClient(this)
}
fun TestButtonFun () {
button.setOnClickListener() {
var _loc:Location= Location("start")
_loc.latitude = _adrees1.latitude
_loc.longitude = _adrees1.longitude
var _loc2:Location= Location("start")
_loc2.latitude = _adress2.latitude
_loc2.longitude = _adress2.longitude
dist = (round(((_loc.distanceTo(_loc2).toDouble()/1000))*100) /100).toDouble()
}
I have also tried this:
var _Lat1 = _adrees1.latitude
var _Lat2 = _adress2.latitude
var _Long1 = _adrees1.longitude
var _Long2 = _adress2.longitude
var _LatRes = _Lat1 - _Lat2
var _longRes = _Long1 - _Long2
var R = 6371000f; // Radius of the earth in m
var dLat = _LatRes * Math.PI / 180f;
var dLon = _longRes * Math.PI / 180f;
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(_Lat1 * Math.PI / 180f) * Math.cos(_Lat2 * Math.PI / 180f) *
Math.sin(dLon/2) * Math.sin(dLon/2);
var c = 2f * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
dist = R* c
You get less distance because you're calculating the radial distance and not the actual route distance.
Try calculating the distance using google directions API.
You can see the difference between radial distance (orange) and actual distance (blue) in the image
I am building some app like image below, I want to force markers not to be clickable, but there is no setClickable(false) for Marker or MarkerOptions.
Currently area around marker (see attachment) is not clickable ( click is passed to marker, not map)
You have to use Overlay instead of marker in the Map to get exactly what you desire. You could follow this link, similar is done in JavaScript here.
I found a way to manually handle clicks for markers.
Add a touchable wrapper as described in this stackoverflow answer: https://stackoverflow.com/a/58039285/1499750
Add a gesture detector to your fragment and listen to single taps, then find the closest marker based on lat lng:
private var gestureDetector: GestureDetector? = null
...
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
gestureDetector = GestureDetector(context, GoogleMapsGestureListener { e -> onMapSingleTap(e) })
//id of touchable wrapper - can use findViewById here instead if not using kotlin synthetics
googleMapsTouchableWrapper?.onTouch = {
gestureDetector?.onTouchEvent(it)
}
}
private fun onMapSingleTap(e: MotionEvent) {
val latLng = map?.projection?.fromScreenLocation(Point(e.x.toInt(), e.y.toInt())) ?: return
//this assumes you are maintaining a set of the latlngs for your markers
val closestNearbyLatLng = markerLatLngs?.findClosestNearbyLatLng(latLng)
//assuming you have a map of latlng to marker you can now find that marker based on latlng and do whatever you need to with it
}
private fun Set<LatLng>.findClosestNearbyLatLng(latLng: LatLng): LatLng? {
val map = map ?: return null
val screenDistance = map.projection.visibleRegion.latLngBounds.northeast.distanceBetweenInKm(map.projection.visibleRegion.latLngBounds.southwest)
val closestLatLng = this.minBy { latLng.distanceBetweenInKm(it) } ?: return null
if (latLng.distanceBetweenInKm(closestLatLng) < screenDistance/40) {
return closestLatLng
}
return null
}
fun LatLong.distanceBetweenInKm(latLng: LatLng): Double {
if (this == latLng) {
return 0.0
}
val earthRadius = 6371.0 //km value;
//converting to radians
val latPoint1Radians = Math.toRadians(latitude)
val lngPoint1Radians = Math.toRadians(longitude)
val latPoint2Radians = Math.toRadians(latLng.latitude)
val lngPoint2Radians = Math.toRadians(latLng.longitude)
var distance = sin((latPoint2Radians - latPoint1Radians) / 2.0).pow(2.0) + (cos(latPoint1Radians) * cos(latPoint2Radians)
* sin((lngPoint2Radians - lngPoint1Radians) / 2.0).pow(2.0))
distance = 2.0 * earthRadius * asin(sqrt(distance))
return abs(distance) //km value
}
class GoogleMapsGestureListener(private val onSingleTap: (MotionEvent) -> Unit) : GestureDetector.SimpleOnGestureListener() {
override fun onSingleTapConfirmed(e: MotionEvent?): Boolean {
super.onSingleTapConfirmed(e)
e?.let { onSingleTap(it) }
return true
}
}
I recently was able to create a formula to create an area surrounding a certain position on a Google Map, that is also scalable with zoom level.
Here I converted the LatLng coordinates from the marker to actual coordinates on the phone:
//array that holds all locations of every marker
//after a marker is created add the position in here
val positionList = mutableListOf<LatLng>()
//map is variable type GoogleMap
map.setOnMapClickListener {
var inRange = false
for(i in positionList.indices) {
//establish corners of boundaries surrounding markers
val points = positionList.toCoordinates(map)
//check if clicked position falls in one of the positions' bounds
val isInRangeLng = (points[i][2]..points[i][3]).contains(it.longitude)
val isInRangeLat = (points[i][0]..points[i][1]).contains(it.latitude)
//if click lands in of the positions' bounds, stop loop and return inRange
//true
if(isInRangeLat && isInRangeLng) {
inRange = true
break
}
}
if(!inRange) {
//APPLY YOUR LOGIC IF CLICK WAS NOT IN AREA
} else {
//APPLY YOUR LOGIC IF CLICK WAS IN AREA
}
}
//Extension function used to simplify logic
/** Convert LatLng to coordinates on phone **/
fun List<LatLng>.toCoordinates(map: GoogleMap): List<List<Double>> {
val proj: Projection = map.projection
val coordinateList = mutableListOf<List<Double>>()
//create bounds for each position in list
this.forEach {
//get screen coordinates at the current LatLng
val point = proj.toScreenLocation(it)
val left = point.x - 100
val right = point.x + 100
val top = point.y - 100
val bottom = point.y + 100
//convert bounds into two points diagonal of each other
val topRight = Point(right, top)
val bottomLeft = Point(left, bottom)
//convert the two points into LatLng points and get the bounds in north,
//south, west, and east
val northEast = proj.fromScreenLocation(topRight)
val north = northEast.latitude
val east = northEast.longitude
val southWest = proj.fromScreenLocation(bottomLeft)
val south = southWest.latitude
val west = southWest.longitude
//add the bounds to be returned in a list which corresponds to a certain
//position
coordinateList.add(listOf(
south,
north,
west,
east
))
}
return coordinateList
}
This can be used for a lot more than markers too.