Extract indices forming a level of RTree - c++

I have a grid made of squares, where each element has of course its own (integer) index. I used boost to create an RTree of bounding boxes for this grid, and I am able to extract a level of the RTree, which consists of a std::vector<BoundingBox> containing all the bounding boxes that make the given level of the rtree.
So far so good.
My goal is now: for a given level of the RTree, how can I know the indices of the cell that are inside each BoundingBox?
For instance, say that my third level is made of 10 bounding boxes. For each one of these 10 bounding boxes, I'd like to know the indices of the original grid that are inside each bounding box.
I think that logically it should be possible to retrieve such an information from the tree structure, but I can't find any example around. Any help is highly appreciated.

There is no external tree traversal (just geometrical queries and enumeration).
I am able to extract a level of the RTree, which consists of a std::vector containing all the bounding boxes that make the given level of the rtree
If you have the bounding boxes, you can of course do a geometrical query for those on the tree. Note that you can composite indexables as tree value-types. For example std::pair<Geom, Index> is built-in:
using Entry = std::pair<Box, Index>;
using Tree = bgi::rtree<Entry, bgi::rstar<16>>;
When you get query results, you'll get the entire entry, so both the cell and the index.
Live On Coliru
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/index/rtree.hpp>
#include <random>
static std::minstd_rand s_prng{std::random_device{}()};
namespace bg = boost::geometry;
namespace bgi = bg::index;
namespace bgm = bg::model;
using Coord = int;
using Index = unsigned;
using Box = bgm::box<bgm::d2::point_xy<Coord>>;
template <unsigned Width, unsigned Height = Width> struct Grid {
static_assert(Width >= 1);
static_assert(Height >= 1);
static auto constexpr Size = Width * Height;
static auto pick_bounding_box() {
using C = std::uniform_int_distribution<Coord>;
auto between = [gen = C{}](Coord lower, Coord upper) mutable {
return gen(s_prng, C::param_type{lower, upper});
};
Coord c = between(0, Width-1), r = between(0, Height-1);
return Box{
{ c, r },
{ between(c + 1, Width), between(r + 1, Height) },
};
}
static auto level3() { return std::vector{pick_bounding_box(), pick_bounding_box(), pick_bounding_box()}; }
using Entry = std::pair<Box, Index>;
using Tree = bgi::rtree<Entry, bgi::rstar<16>>;
static Box cell(Index idx) {
assert(idx < Size);
Coord row = idx / Width;
Coord col = idx % Width;
return Box{{col + 0, row + 0}, {col + 1, row + 1}};
}
static Tree build() {
Tree tree;
for (Index idx = 0; idx < Size; ++idx)
tree.insert({cell(idx), idx});
return tree;
}
};
#include <fmt/ostream.h>
#include <fmt/ranges.h>
template <typename Geom>
struct fmt::formatter<bg::detail::dsv::dsv_manipulator<Geom>> : fmt::ostream_formatter {};
using bg::dsv;
using bgi::adaptors::queried;
int main() {
using G = Grid<12, 6>;
using Cells = std::set<Index>;
auto const tree = G::build();
Cells cells;
for (auto&& bbox : G::level3()) {
fmt::print("Within bbox {}:\n", dsv(bbox));
for (auto& [cell, idx] : tree | queried(bgi::within(bbox))) {
cells.insert(idx);
fmt::print(" - cell {} with index {}\n", dsv(cell), idx);
}
}
fmt::print("All {} level-3 cells: {}\n", cells.size(), cells);
}
With sample output:
Within bbox ((8, 0), (12, 3)):
- cell ((8, 0), (9, 1)) with index 8
- cell ((8, 1), (9, 2)) with index 20
- cell ((8, 2), (9, 3)) with index 32
- cell ((9, 0), (10, 1)) with index 9
- cell ((11, 0), (12, 1)) with index 11
- cell ((9, 2), (10, 3)) with index 33
- cell ((10, 1), (11, 2)) with index 22
- cell ((11, 2), (12, 3)) with index 35
- cell ((10, 2), (11, 3)) with index 34
- cell ((11, 1), (12, 2)) with index 23
- cell ((10, 0), (11, 1)) with index 10
- cell ((9, 1), (10, 2)) with index 21
Within bbox ((2, 3), (5, 5)):
- cell ((3, 3), (4, 4)) with index 39
- cell ((2, 3), (3, 4)) with index 38
- cell ((4, 3), (5, 4)) with index 40
- cell ((2, 4), (3, 5)) with index 50
- cell ((4, 4), (5, 5)) with index 52
- cell ((3, 4), (4, 5)) with index 51
Within bbox ((2, 5), (6, 6)):
- cell ((3, 5), (4, 6)) with index 63
- cell ((2, 5), (3, 6)) with index 62
- cell ((4, 5), (5, 6)) with index 64
- cell ((5, 5), (6, 6)) with index 65
All 22 level-3 cells: {8, 9, 10, 11, 20, 21, 22, 23, 32, 33, 34, 35, 38, 39, 40, 50, 51, 52, 62, 63, 64, 65}

Related

How to filter a list of tuples with (Int, Int) values by a predicate applied to their respective first and second values?

Suppose i have a list of tuples representing positions on a grid by their x and y values.
The tuples are defined as type Pos, a pair of Integer values.
The Board is further defined as a list of Pos.
type Pos = (Int, Int)
type Board = [Pos]
exampleBoard :: Board
exampleBoard = [(1, 1), (1, 2), (2, 2), (2, 3), (1, 3),
(5, 1), (5, 2), (4, 2), (4, 1), (5, 3),
(9, 10), (9, 11), (9, 12), (9, 13),
(10, 10), (10, 11), (10, 12), (10, 13),
(10, 20), (11, 20), (12, 20), (13, 20)]
The Board is a x*x grid, where you can always consider the known variables height and width having the same value. height = width = size
If the x or y value is not in a certain range (0<x<size || 0<y<size) I want the tuple removed.
Is there a simple way to filter the list as I describe? From searching for similar questions I have tried using library functions such as "break" and "span" to no success as of yet.
To test if a tuple (Int,Int) is in a given range, you can use the inRange function:
import Data.Ix (inRange)
inRange ((1,1),(10,10)) (5,5) -- True
inRange ((1,1),(10,10)) (11,6) -- False
filter (inRange ((1,1),(10,10))) [(5,5),(11,6)] -- [(5,5)]

How to calculate distances from coordinates stored in lists

So far I managed to calculate the distances between an Point P(x,y) and a multitude of points stored in a list l = [(x1,y1), (x2,y2), (x3,y3), ...) Here is the code :
import math
import pprint
l = [(1,2), (2,3), (4,5)]
p = (3,3)
dists = [math.sqrt((p[0]-l0)**2 + (p[1]-l1)**2) for l0, l1 in l]
pprint.pprint(dists)
Output :
[2.23606797749979, 1.0, 2.23606797749979]
Now I want to calculate the distances from multitude points in a new list to the points in the list l.
I haven't found a solution yet, so does anyone have an idea how this could be done?
Here is a possible solution:
from math import sqrt
def distance(p1, p2):
return sqrt((p1[0]-p2[0])**2 + (p1[1]-p2[1])**2)
lst1 = [(1,2), (2,3), (4,5)]
lst2 = [(6,7), (8,9), (10,11)]
for p1 in lst1:
for p2 in lst2:
d = distance(p1, p2)
print(f'Distance between {p1} and {p2}: {d}')
Output:
Distance between (1, 2) and (6, 7): 7.0710678118654755
Distance between (1, 2) and (8, 9): 9.899494936611665
Distance between (1, 2) and (10, 11): 12.727922061357855
Distance between (2, 3) and (6, 7): 5.656854249492381
Distance between (2, 3) and (8, 9): 8.48528137423857
Distance between (2, 3) and (10, 11): 11.313708498984761
Distance between (4, 5) and (6, 7): 2.8284271247461903
Distance between (4, 5) and (8, 9): 5.656854249492381
Distance between (4, 5) and (10, 11): 8.48528137423857

Python - Compare Tuples in a List

So in a program I am creating I have a list that contains tuples, and each tuple contains 3 numbers. For example...
my_list = [(1, 2, 4), (2, 4, 1), (1, 5, 2), (1, 4, 1),...]
Now I want to delete any tuple whose last two numbers are less than any other tuple's last two numbers are.
The first number has to be the same to delete the tuple. *
So with the list of tuples above this would happen...
my_list = [(1, 2, 4), (2, 4, 1), (1, 5, 2), (1, 4, 1),...]
# some code...
result = [(1, 2, 4), (2, 4, 1), (1, 5, 2)]
The first tuple is not deleted because (2 and 4) are not less than (4 and 1 -> 2 < 4 but 4 > 1), (1 and 5 -> 2 > 1), or (4 and 1 -> 2 < 4 but 4 > 1)
The second tuple is not deleted because its first number (2) is different than every other tuples first number.
The third tuple is not deleted for the same reason the first tuple is not deleted.
The fourth tuple is deleted because (4 and 1) is less than (5 and 2 -> 4 < 5 and 1 < 2)
I really need help because I am stuck in my program and I have no idea what to do. I'm not asking for a solution, but just some guidance as to how to even begin solving this. Thank you so much!
I think this might actually work. I just figured it out. Is this the best solution?
results = [(1, 2, 4), (2, 4, 1), (1, 5, 2), (1, 4, 1)]
for position in results:
for check in results:
if position[0] == check[0] and position[1] < check[1] and position[2] < check[2]:
results.remove(position)
Simple list comprehension to do this:
[i for i in l if not any([i[0]==j[0] and i[1]<j[1] and i[2]<j[2] for j in my_list])]
Your loop would work too, but be sure not to modify the list as you are iterating over it.
my_list = [(1, 2, 4), (2, 4, 1), (1, 5, 2), (1, 4, 1)]
results = []
for position in my_list:
for check in my_list:
if not (position[0] == check[0] and position[1] < check[1] and position[2] < check[2]):
results.append(position)
results
>[(1, 2, 4), (2, 4, 1), (1, 5, 2)]

How to get a polygon from boost::geometry::model::polygon?

I'm trying to calculate a difference of two polygons using boost::geometry::difference with boost::geometry::model::polygon representing my polygons.
In case when the first polygon contains the second one result of the operation is a single boost::geometry::model::polygon with the inner and outer rings populated with coordinates of the source polygons.
How do I get a polygon (in the elementary geometry sense) from boost::geometry::model::polygon?
Clarification:
In elementary geometry, a polygon is a plane figure that is bounded by a finite chain of straight line segments closing in a loop to form a closed chain or circuit.
The outer ring of boost::geometry::model::polygon is a polygon, the inner rings are polygons too. As a whole boost::geometry::model::polygon is not a polygon.
So, what I'm asking: How to convert boost::geometry::model::polygon to a normal polygon (having a single chain of straight line segments), which represents the same area on a plane.
Here's what I'm trying to achieve:
polygon1 = (0,0), (0,8), (8,8), (8,0), (0,0)
polygon2 = (2,2), (2,6), (6,6), (6,2), (2,2)
Polygons 1 & 2 in green / oker:
difference = (0,0), (0,4), (2,4), (2,2), (6,2), (6,6), (2,6), (2,4), (0,4), (0,8), (8,8), (8,0), (0,0)
Expected difference in grey:
I know the same boost::geometry::model::polygon having inner rings could be represented by infinitely many different normal polygons. I don't care which one I get.
You can easily construct a ring that models your expected weak simple polygon. First:
Caveat
Note though that the result isn't valid for further use with the Boost Geometry library's algorithms.
Take your literal example:
std::string reason;
poly expected;
bg::read_wkt("POLYGON((0 0, 0 4, 2 4, 2 2, 6 2, 6 6, 2 6, 2 4, 0 4, 0 8, 8 8, 8 0, 0 0))", expected);
bool ok = bg::is_valid(expected, reason);
std::cout << "Expected: " << bg::dsv(expected) << (ok?" valid":" invalid: '" + reason + "'") << "\n";
Prints
Expected: (((0, 0), (0, 4), (2, 4), (2, 2), (6, 2), (6, 6), (2, 6), (2, 4), (0, 4), (0, 8), (8, 8), (8, 0), (0, 0))) invalid: 'Geometry has invalid self-intersections. A self-intersection point was found at (0, 4); method: t; operations: x/u; segment IDs {source, multi, ring, segment}: {0, -1, -1, 0}/{0, -1, -1, 7}'
Algorithm implementation
With that out of the way, here's a simple algorithm to construct the simple weak polygon from a given polygon:
ring weak_simple_ring(poly& p) {
ring r = p.outer();
for (auto& i: p.inners()) {
auto last = r.back();
r.insert(r.end(), i.rbegin(), i.rend());
r.insert(r.end(), last);
}
return r;
}
The only subtler point there is to reverse the direction (CW/CCW) of the inner rings to match that of the outer ring.
The algorithm doesn't attempt to be smart about finding a cut-point to the inner ring, which probably also means that it won't work nicely for the generic case with multiple inner rings.
DEMO
Here's a full live demo
Live On Coliru
Where the input is
bg::read_wkt("POLYGON((0 0,0 10,10 10,10 0,0 0))", a);
bg::read_wkt("POLYGON((2 2, 2 6, 6 6, 6 2, 2 2))", b);
The transformation is
std::vector<poly> output;
bg::difference(a, b, output);
for (auto& p : output) {
ring r = weak_simple_ring(p);
bg::convert(r, p);
}
And the result becomes
More complicated sample
Consider when b had a hole:
bg::read_wkt("POLYGON((0 0,0 10,10 10,10 0,0 0))", a);
bg::read_wkt("POLYGON((2 2, 2 6, 6 6, 6 2, 2 2)(3 3, 5 3, 5 5, 3 5, 3 3))", b);
The output with the same code becomes
This is the old answer. After edits to the question I've posted a simple implementation of an algorithm that suits the sample given
It already is.
If you mean, a "simple" non-holey polygon, the outer ring is all you want. Just discard the inner rings.
However, in the most generic case you can end up with multiple entirely disjunct polygons, which is why the output is a collection of polygons. You will have to consider this possibility too (optionally joining the different result polygons into one and discarding inner rings if that's what you desire, functionally).
A sample:
bg::read_wkt("POLYGON((0 0,0 10,10 10,10 0,0 0))", a);
bg::read_wkt("POLYGON((2 -2,2 12,5 12,5 -2,2 -2))", b);
Here, b cuts a into two separate pieces. So you must be prepared to handle multiple, disjunct, output polygons:
Live On Coliru
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/io/io.hpp>
#include <iostream>
#include <fstream>
namespace bg = boost::geometry;
using pt = bg::model::d2::point_xy<int>;
using poly = bg::model::polygon<pt>;
int main() {
poly a, b;
bg::read_wkt("POLYGON((0 0,0 10,10 10,10 0,0 0))", a);
bg::read_wkt("POLYGON((2 -2,2 12,5 12,5 -2,2 -2))", b);
std::cout << bg::dsv(a) << "\n";
std::cout << bg::dsv(b) << "\n";
{
std::ofstream svg("/tmp/input.svg");
boost::geometry::svg_mapper<pt> mapper(svg, 400, 400);
mapper.add(a);
mapper.add(b);
mapper.map(a, "fill-opacity:0.5;fill:rgb(153,204,0);stroke:rgb(153,204,0);stroke-width:2");
mapper.map(b, "fill-opacity:0.5;fill:rgb(204,153,0);stroke:rgb(202,153,0);stroke-width:2");
}
std::vector<poly> output;
bg::difference(a, b, output);
for (auto& p : output)
std::cout << "\n\t" << bg::dsv(p);
{
std::ofstream svg("/tmp/output.svg");
boost::geometry::svg_mapper<pt> mapper(svg, 400, 400);
assert(output.size() == 2);
mapper.add(output[0]);
mapper.add(output[1]);
mapper.add(b);
mapper.map(output[0], "fill-opacity:0.5;fill:rgb(153,204,0);stroke:rgb(153,204,0);stroke-width:2");
mapper.map(output[1], "fill-opacity:0.5;fill:rgb(153,204,0);stroke:rgb(153,204,0);stroke-width:2");
mapper.map(b, "fill-opacity:0.15;fill:rgb(153,153,153);stroke-width:0");
}
}
Prints:
(((0, 0), (0, 10), (10, 10), (10, 0), (0, 0)))
(((2, -2), (2, 12), (5, 12), (5, -2), (2, -2)))
(((5, 10), (10, 10), (10, 0), (5, 0), (5, 10)))
(((2, 10), (2, 0), (0, 0), (0, 10), (2, 10)))
SVGs rendered:

Elegant way the find the Vertices of a Cube

Nearly every OpenGL tutorial lets you implement drawing a cube. Therefore the vertices of the cube are needed. In the example code I saw a long list defining every vertex. But I would like to compute the vertices of a cube rather that using a overlong list of precomputed coordinates.
A cube is made of eight vertices and twelve triangles. Vertices are defined by x, y, and z. Triangles are defined each by the indexes of three vertices.
Is there an elegant way to compute the vertices and the element indexes of a cube?
When i was "porting" the csg.js project to Java I've found some cute code which generated cube with selected center point and radius. (I know it's JS, but anyway)
// Construct an axis-aligned solid cuboid. Optional parameters are `center` and
// `radius`, which default to `[0, 0, 0]` and `[1, 1, 1]`. The radius can be
// specified using a single number or a list of three numbers, one for each axis.
//
// Example code:
//
// var cube = CSG.cube({
// center: [0, 0, 0],
// radius: 1
// });
CSG.cube = function(options) {
options = options || {};
var c = new CSG.Vector(options.center || [0, 0, 0]);
var r = !options.radius ? [1, 1, 1] : options.radius.length ?
options.radius : [options.radius, options.radius, options.radius];
return CSG.fromPolygons([
[[0, 4, 6, 2], [-1, 0, 0]],
[[1, 3, 7, 5], [+1, 0, 0]],
[[0, 1, 5, 4], [0, -1, 0]],
[[2, 6, 7, 3], [0, +1, 0]],
[[0, 2, 3, 1], [0, 0, -1]],
[[4, 5, 7, 6], [0, 0, +1]]
].map(function(info) {
return new CSG.Polygon(info[0].map(function(i) {
var pos = new CSG.Vector(
c.x + r[0] * (2 * !!(i & 1) - 1),
c.y + r[1] * (2 * !!(i & 2) - 1),
c.z + r[2] * (2 * !!(i & 4) - 1)
);
return new CSG.Vertex(pos, new CSG.Vector(info[1]));
}));
}));
};
I solved this problem with this piece code (C#):
public CubeShape(Coord3 startPos, int size) {
int l = size / 2;
verts = new Coord3[8];
for (int i = 0; i < 8; i++) {
verts[i] = new Coord3(
(i & 4) != 0 ? l : -l,
(i & 2) != 0 ? l : -l,
(i & 1) != 0 ? l : -l) + startPos;
}
tris = new Tris[12];
int vertCount = 0;
void AddVert(int one, int two, int three) =>
tris[vertCount++] = new Tris(verts[one], verts[two], verts[three]);
for (int i = 0; i < 3; i++) {
int v1 = 1 << i;
int v2 = v1 == 4 ? 1 : v1 << 1;
AddVert(0, v1, v2);
AddVert(v1 + v2, v2, v1);
AddVert(7, 7 - v2, 7 - v1);
AddVert(7 - (v1 + v2), 7 - v1, 7 - v2);
}
}
If you want to understand more of what is going on, you can check out the github page I wrote that explains it.