-
Notifications
You must be signed in to change notification settings - Fork 507
Description
Motivation / Problem
The region management that was introduced in revision 1.11.x tries to reduce the spreading of floods to limit network congestion.
It's a static approach that requires individual configuration that matches some but not all needs depending on the location of senders and receivers. I think this approach allows too much flood spreading in areas where packages are not intended and blocks flood spreading to areas that should be covered intentionally by the sender.
I'd like to see a more flexible approach that limits the number of flooding repeaters without a fixed definition of allowed regions and local limitations.
Problem Solution
Currently I don't see that the adverted geo-coordinates of companions and repeaters are used as part of flooding decisions; I think geo-coordinates should be included:
Looking at paths of received adverts the package route reflects real world corridors between sender and receiver. Geo formations like valleys, mountains or shore lines change direct corridors to corridors with multiple edges. Looking at paths of incoming adverts I currently can define working path lists for direct messaging or tracing. This information can be used as well to predefine a corridor my flood packages should take. Besides an individual, manual definition a "rich device" (MeshCore App on a smartphone) could auto-define reasonable corridors using past communication and information from maps (corridor along shorelines ...).
A repeater would re-transmit the flood package only if it's inside the defined corridor that is sent as part of the package header.
Corridor Definition
Think about the corridor is defined as a list of triples: latitude, longitude, radius.
A single triple could be compressed to 4 bytes:
- 14 bit for the latitude (precision below 1 km)
- 14 bit for the longitude (precision below 1 km)
- 4 bit for a radius: 16 values with a fixed stretch factor to support for example 2 km up to 200 km
So the corridor in the following image could be defined with 12 bytes. Only the repeaters marked in green inside the corridor re-transmit the sent packet.
Samples for Corridor Usage to reduce Flood Traffic
- send out a flood advert to a remote location where you expect a communication partner to be without a regional limitation and without too much load on the whole network.
- re-transmit a direct message that was not ACKed to a companion with a known target position; use a direct corridor with (own_position, radius_small) (target_position, radius_small) if there is no detailed corridor with multiple edges.
- re-transmit a direct message that was not ACKed within an increased corridor (own_position, radius_large) (target_position, radius_large) before falling back to a common flood.
Repeater Corridor Check
The following source code demonstrates how a repeater could check very efficiently if its own position is inside the corridor definition from the package header:
#include <iostream>
// g++ -o isPointInCorridorTest isPointInCorridorTest.cpp
struct Circle
{
float x; // lat
float y; // lon
float r; // radius
};
inline bool isPointInsideConnectedCirclesN(
float px,
float py,
const Circle* circles,
int count
)
{
// Special case: no circles
if (count <= 0)
return false;
// Special case: exactly one circle
if (count == 1)
{
float dx = px - circles[0].x;
float dy = py - circles[0].y;
return (dx * dx + dy * dy) <= (circles[0].r * circles[0].r);
}
// Iterate over all segments
for (int i = 0; i < count - 1; ++i)
{
const Circle& c1 = circles[i];
const Circle& c2 = circles[i + 1];
// Connection vector
float vx = c2.x - c1.x;
float vy = c2.y - c1.y;
// Squared length
float len_sq = vx * vx + vy * vy;
// Degenerate case: identical centers
if (len_sq == 0.0f)
{
float dx = px - c1.x;
float dy = py - c1.y;
if ((dx * dx + dy * dy) <= (c1.r * c1.r))
return true;
continue;
}
// Vector from first center to point
float wx = px - c1.x;
float wy = py - c1.y;
// Projection parameter
float t = (wx * vx + wy * vy) / len_sq;
// Clamp to [0, 1]
if (t < 0.0f) t = 0.0f;
else if (t > 1.0f) t = 1.0f;
// Projected point on the axis
float ax = c1.x + t * vx;
float ay = c1.y + t * vy;
// Interpolated radius
float r = c1.r + t * (c2.r - c1.r);
// Distance from point to axis
float dx = px - ax;
float dy = py - ay;
if ((dx * dx + dy * dy) <= (r * r))
return true;
}
return false;
}
int main()
{
// Test data: 3 circles
Circle circles[] = {
{52.0f, 13.0f, 0.5f}, // Circle 1
{52.5f, 13.2f, 0.4f}, // Circle 2
{53.0f, 13.5f, 0.6f} // Circle 3
};
int circleCount = sizeof(circles) / sizeof(circles[0]);
// Test points
float testPoints[][2] = {
{52.0f, 13.0f}, // exactly Circle 1
{52.4f, 13.15f}, // inside corridor between Circle 1 and 2
{54.1f, 14.6f}, // outside all circles/corridors
{52.75f, 13.35f} // inside corridor between Circle 2 and 3
};
for (int i = 0; i < 4; ++i)
{
float px = testPoints[i][0];
float py = testPoints[i][1];
bool inside = isPointInsideConnectedCirclesN(px, py, circles, circleCount);
std::cout << "Point (" << px << ", " << py << ") is "
<< (inside ? "INSIDE" : "OUTSIDE")
<< " the connected body." << std::endl;
}
return 0;
}
Conclusion
With the corridor approach:
- network traffic could be reduced within local and targeted long range communication
- routes can be predefined to travel in areas with network coverage (along shore lines, outside of specific countries, ...)
- repeater downstream compatibility can be kept: repeaters not checking their relative position keep to re-transmit flood packages like today
- the approach can be used as an intermediate step between direct communication and the flood fallback