Reputation: 2184
I am working on a sort of route planner and I'm not happy with the amount of repetitive code I've written especially with the calculations which are a real "rinse and repeat" affair. I was wondering if anyone could suggest (giving an example) a way for me to perhaps reduce this code?
At the moment I use $.each
to grab values from input fields and I store them in an object
. After this point, I access each defined object individually to perform calculations and work. I think I have perhaps overengineered this a bit!
Let me start by showing you the simple HTML that houses the input fields from which I gather my data.
<div id="plot1" class="plotrow">
<div class="lat">
<input id="plot1_lat" />
</div>
<div class="lon">
<input id="plot1_long" />
</div>
</div>
<div id="plot2" class="plotrow">
<div class="lat">
<input id="plot2_lat" />
</div>
<div class="lon">
<input id="plot2_long" />
</div>
</div>
...
Ok, at this stage I move to jQuery to grab any values (which will be latitude and longitude coordinates). I store this information in an object.
//Object is defined
var obj = {};
//Values are passed in
$('.plotrow').each(function () {
obj[this.id] = {
lat: $(this).find('.lat input').val(),
lon: $(this).find('.lon input').val()
};
});
At this stage I need to start doing work to my gathered information. Here I pass the values to a function that converts them to radians.
plot1LatRad = deg2rad(obj.plot1.lat);
plot1LonRad = deg2rad(obj.plot1.lon);
plot2LatRad = deg2rad(obj.plot2.lat);
plot2LonRad = deg2rad(obj.plot2.lon);
plot3LatRad = deg2rad(obj.plot3.lat);
plot3LonRad = deg2rad(obj.plot3.lon);
As you can see I am access each plot value individually. Here is what happens next, I work out differences between locations.
//Location A
var AtoBLat = plot2LatRad - plot1LatRad;
var AtoBLon = plot2LonRad - plot1LonRad;
AtoBSum = Math.pow(Math.sin(AtoBLat / 2), 2) + Math.cos(plot1LatRad) * Math.cos(plot2LatRad) * Math.pow(Math.sin(AtoBLon / 2), 2);
AtoBSqrt = 2 * Math.atan2(Math.sqrt(AtoBSum), Math.sqrt(1 - AtoBSum));
AtoBMiles = AtoBSqrt * Rm;
AtoBRound = round(AtoBMiles);
miles1 = AtoBRound * 0.86898;
//Location B
var BtoCLat = plot3LatRad - plot2LatRad;
var BtoCLon = plot3LonRad - plot2LonRad;
BtoCSum = Math.pow(Math.sin(BtoCLat / 2), 2) + Math.cos(plot2LatRad) * Math.cos(plot3LatRad) * Math.pow(Math.sin(BtoCLon / 2), 2);
BtoCSqrt = 2 * Math.atan2(Math.sqrt(BtoCSum), Math.sqrt(1 - BtoCSum));
BtoCMiles = BtoCSqrt * Rm;
BtoCRound = round(BtoCMiles);
miles2 = BtoCRound * 0.86898;
As you can see it's all getting very repetitive and quite bloated. Can I do this work in a loop? Can anyone suggest an approach that would help? For the sake of brevity I've only shown a couple of points but this application has as many as 10 areas you can plot a route too and so the above code will become quite big.
Upvotes: 0
Views: 66
Reputation:
There is an error because I don't know what Rm
is :
$("form").append(
template("plot1"),
template("plot2"),
"<input type=\"submit\">"
).on("submit", function (ev) {
ev.preventDefault();
calculateMiles(
this.elements.plot1_lat.value,
this.elements.plot1_long.value,
this.elements.plot2_lat.value,
this.elements.plot2_long.value
);
});
function template (id) {
return ""
+ "<div id=\"" + id + "\" class=\"plotrow\">"
+ "<div class=\"lat\">"
+ id + " lat <input name=\"" + id + "_lat\" />"
+ "</div>"
+ "<div class=\"lon\">"
+ id + " lng <input name=\"" + id + "_long\" />"
+ "</div>"
+ "</div>";
}
function calculateMiles (plot1LatRad, plot1LonRad, plot2LatRad, plot2LonRad) {
var AtoBLat = plot2LatRad - plot1LatRad;
var AtoBLon = plot2LonRad - plot1LonRad;
var AtoBSum = Math.pow(Math.sin(AtoBLat / 2), 2) + Math.cos(plot1LatRad) * Math.cos(plot2LatRad) * Math.pow(Math.sin(AtoBLon / 2), 2);
var AtoBSqrt = 2 * Math.atan2(Math.sqrt(AtoBSum), Math.sqrt(1 - AtoBSum));
var AtoBMiles = AtoBSqrt * Rm;
var AtoBRound = round(AtoBMiles);
return AtoBRound * 0.86898;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form></form>
Upvotes: 0
Reputation: 5283
You are correct in the fact that the code can explode if you have multiple plots, but that's why functions and loops exist. Below, I am suggesting a solution with a function locationDiff
that takes two plot configurations and spits out the distance between them as you want, a loop is later introduced to cycle through the configurations object and store the results in a final array.
// does the distance calculation between two plot configurations
function locationDiff(plot1, plot2) {
let AtoBLat = deg2rad(plot2.lat) - deg2rad(plot1.lat);
let AtoBLon = deg2rad(plot2.lon) - deg2rad(plot1.lon);
let AtoBSum = Math.pow(Math.sin(AtoBLat / 2), 2) + Math.cos(deg2rad(plot1.lat)) * Math.cos(deg2rad(plot2.lat)) * Math.pow(Math.sin(AtoBLon / 2), 2);
return (round((2 * Math.atan2(Math.sqrt(AtoBSum), Math.sqrt(1 - AtoBSum))) * Rm) * 0.86898);
}
// stores the results of calling `locationDiff` on the plots
let diffs = [];
// captures the keys of the different plot configurations
let objKeys = Object.keys(obj);
// loops through the keys to calculate and store the distances
objKeys.forEach((key, index) => {
// the next key in the keys array
let nextKey = objKeys[index + 1];
// if not at the end of the array yet, push the result in the final array
if (nextKey) {
diffs.push(locationDiff(obj[key], obj[nextKey]));
}
});
Hope this helps.
Upvotes: 1