Converting Miles to Degrees for postgis Sequelize - node.js

I am querying the PostGres database using POSTGIS extension as I want to get users in a radius.
I am following this post, where the following code is working fine:
Alert.findAll({
where: Sequelize.where(
Sequelize.fn('ST_DWithin',
Sequelize.col('position'),
Sequelize.fn('ST_SetSRID',
Sequelize.fn('ST_MakePoint',
req.query.long, req.query.lat),
4326),
0.032),
true)
})
.then(alerts => res.send(alerts))
.catch(next)
But I am encountering a strange problem, the radius is defined in degrees not miles, e.g. they said
Sample query to find all within 0.032 deg which is approximately 2 miles.
Then to customize the radius & validate my solution against above statement, I searched a lot and I wasn't able to find any formula to convert my miles into radius say I want to check in the radius of 10 miles. Then I checked this stack question, and run some calculations based on the formulas given in the accepted answer, using miles as 2 instead of 100, just to ensure if the approximation is correct but the answer was 0.42 not 0.32. e.g.
const latTraveledMiles = 2;
const latTraveledKM = 2 * 0.621371;
const latTraveledDeg = (1 / 110.54) * latTraveledKM;
const currentLat = 74.0064;
const longTraveledMiles = 2;
const longTraveledKM = 2 * 0.621371;
const longTraveledDeg = (1 / (111.320 * Math.cos(currentLat))) * longTraveledKM;
let degrees = Math.sqrt(Math.pow(latTraveledDeg, 2), Math.pow(longTraveledDeg, 2)); //should be 0.32

To make things easier, I would suggest you cast the geometry column position and ST_MakePoint to geography which will allow you to use metric input. You can read more about it here https://www.crunchydata.com/blog/postgis-and-the-geography-type
To add a geography column to your table you can use the following statement
-- first you add the column of type geography
ALTER TABLE your_table ADD COLUMN geog geography(point, 4326);
-- afterwards you populate it from your geometry column which is position
UPDATE your_table SET geog = position::geography;
You can now use ST_DWithin(geography gg1, geography gg2, double precision distance_meters); in your javascript logic, hence just substitute your radius value with 2*1.609344*1000 which translates to 2 miles times the factor to kilometers times 1000 to yield that value in meters.

Related

Azure Maps Control With Weighted Heat Map Layer

I am creating a web page that has a Heat Map on it using Azure Maps.
I have the heat map successfully pulling in points and displaying, but I need to change how it is rendering.
Specifically my heat map needs to be based on length of time in an area - which can be accomplished by looking at the timestamp that is on my data points. Any ideas on how to accomplish this in the heat map layer using DateTime like values?
The HeatMapLayer class has an option called weight that can take a data driven style expression that provides a number between 0 and 1 to indicate the weight. In your case you are working with timestamps, so you will first want to decide what your time range for min and max values should be. If your timestamps are strings, you should loop through your data before adding it to the data source and calculate the integer value for the data and store it as a property in the feature (i.e. time). For example: new Date('2022-2-14T03:24:00').getTime()
For example, you might want the max value to be anything that has occurred in the current minute (0ms), and the min value to occur on anything that is 15 minutes (900,000ms) or older. You can then put together a formula that makes use of the integer date to get a scalar value between 0 and 1. Here is the math using plain JavaScript:
var timeRange = 900000; //15 minutes
var now = Date.now();
var time = new Date('2022-2-14T03:24:00').getTime();
//Calculate the time offset and snap to the 0 to 15 minute range.
var dt = Math.max(0, Math.min(timeRange, now - time))
//We want the inverse weight since smaller dt should be higher. Thus 1 minus ratio.
var weight = 1 - dt/timeRange;
This can then be turned into a data driven expression and set as the weight value in the heat map layer options.
var timeRange = 900000; //15 minutes
var now = Date.now();
map.layers.add(new atlas.layer.HeatMapLayer(datasource, null, {
weight: ['-', 1, ['/', ['max', 0, ['min', ['-', now, ['get', 'time']], timeRange]], timeRange]]timeRange]]
}), 'labels');
If you want to update the now value periodically you can rebuild the expression and update the heat map using the setOptions function. For example;
var timeRange = 900000; //15 minutes
function getWeightExp(){
var now = Date.now();
return ['-', 1, ['/', ['max', 0, ['min', ['-', now, ['get', 'time']], timeRange]], timeRange]];
}
//Create heatmap layer.
var heatMap = new atlas.layer.HeatMapLayer(datasource, null, {
//Set weight option.
weight: getWeightExp()
});
//Add the heatmap to the map.
map.layers.add(heatMap, 'labels');
//Set an update frequency. In this case once a minute.
setTimeout(function() {
heatMap.setOptions({
weight: getWeightExp()
});
}, 60000);

Update SQLite row with certain number

I have a problem that I can't solve with better-sqlite3 on node.js
I have a table looking somewhat like this:
image of table
How can I change each rows xp, that has a level of 3 to 100? So in this example it should change id's 1 and 4 xp value to 100.
Any help is appreciated!
This is a pretty basic SQL Query, you're just needing to do a WHERE on all levels that equal 3.
UPDATE tableName
SET level = 100
WHERE level = 3
Looking at the better-sqlite3 documentation, to do an UPDATE you simply need to call the function using run()
const stmt = db.prepare('UPDATE tableName SET level = ? WHERE level = ?');
const info = stmt.run(3, 100);

Using multi-layer queries in Solr

The Solr "qf" parameter works as follows:
Let's say I have: query = "sid" and qf = [field1, field1_edge, field2, field2_edge].
The Solr score is calculated as follows:
max(f1, f1_e, f2, f2_e) + tie * (sum of other 3 fields) where: "tie" lies in [0,1]
Let's call: winner1 = field with max(f1, f1_e) and
winner2 = field with max(f2, f2_e)
I would like to score a given query in Solr as follows:
score1 = winner1_score + tie_1 * loser1_score
score2 = winner2_score + tie_1 * loser2_score
final score = score1 + tie_2 * score2
Effectively, I want to apply qf in two layers (taking tie_1 = 0 and tie_2 = 1). What are my options to implement this idea of relevance? I think neither "qf" parameter nor function boosts support this.
Thanks!
It seems to me that's the way to do it is to use the query function which allows you to apply functions to queries.
You combine this with nested query parsers which allows you to run multiple dismax queries.
You can do something like this (where you set tie1 and tie2 according to what you want):
q=_val_:"add(query($qq1),product(query($qq2),${tie2}))"
qq1={!edismax qf='field1 field1_edge' v='sid' tie=${tie1}}
qq2={!edismax qf='field2 field2_edge' v='sid' tie=${tie1}}
tie1=0.5
tie2=0.3
If you used Solr 7.2 (or higher) you also need to set uf=_query_ * in order for the _val_ hook to work.
P.S: it should be possible (though I haven't tested it) to move the content of q into the qf parameter and that way you don't have to use the _val_ hook:
qf=add(query($qq1),product(query($qq2),${tie2}))

Displaying the total sum of values from strings

My project is a simple shopping game where the user types in the quantity amount, and the value of the individual prices appears and then a total sum can appear below.
I have managed to create the part of displaying the individual product price but i am confused on how to add the total sum and display correctly at the instance that i defined.
Some info
Actionscript will check for keypress event
sample of code snippet:
if(e.keyCode == 49){ //1
trace("Key Code Pressed: " + e.keyCode);
amount1.text = "1.00"
}
...
var total:Number = amount1+ amount2+amount3+amount4+amount5;
output1.text = String(total);
From the code above, when the user types 1, the price will change to "1.00" on the price instance field (dynamic text type).
Picture below:
A sample of my game running:
Total price should be $13.00 dollars..
Is there any way to make this happen? I believe is it something to do with parseint.
You should be able to string together multiple parseint statements like this:
var total:number = parseint(amount1.text) + parseint(amount2.text) + parseint(amount3.text) + parseint(amount4.text) + parseint(amount5.text);
output1.text = total;
If you go this route, you will need to handle stituations that involve NaN
Here is the documentation on parseint if you haven't already, you should look at it. http://help.adobe.com/en_US/AS2LCR/Flash_10.0/help.html?content=00000590.html

Get objects with max value from grouped by linq query

I got the following linq query:
var invadersOrderedInColumns = from i in invaders
group i by i.GetPosition().X;
This will order the invaders with the same X position. The next thing I want to do is retrieve the invader with the highest Y value from each of those columns.
Imagine if you will each invader as a black blok in the following image. This will represent the invaders after the above linq query. Each X = Value is the key.
Now, from each of these groups (columns), I want to get the invaders with the highest Y position (so the bottom invader of each column when you look at the picture):
How can I get this done with a Linq query?
I don't much care for the query syntax, but in extension method syntax it would look something like this.
var invadersOrderedInColumns = invaders
.GroupBy(d => d.GetPosition().X)
.Select(d => d.OrderByDescending(y => y.GetPosition().Y).First());

Resources