I want to write a method for my Cuboid class which returns the cuboid defined by the intersection of two cuboids.
A cuboid is internally represented by an origin point and a terminus point such that the vector from the origin to the terminus is necessarily positive in all dimensions.
As a starting point (maybe helpful maybe not) the following method (in ruby) determines whether or not the two cuboids intersect.
def intersects? other_cuboid
return not( self.top < other_cuboid.bottom ||
self.bottom > other_cuboid.top ||
self.left > other_cuboid.right ||
self.right < other_cuboid.left ||
self.front < other_cuboid.back ||
self.back > other_cuboid.front )
end
Intuitively it seems that there should be a fairly parsimonious solution to this problem but i can't think of it... any ideas?
Note: the cuboids are necessarily aligned to the axes
Is it okay that your definition of cuboids depends on your initial choice of basis?
If all cuboids begin at the origin and then move into the positive direction of each axis, then is the intersection not just the minimum of all the co-ordinates in each direction? i.e. intersection = min(left1, left2), min(right1, right2), etc. Not sure I understand exactly what your cuboids are, or what you want them to be.
Alternatively if your cuboids are aligned in each direction (as it looks like they are from your definition), then you can take the new cuboid to have:
bottom = max(bottom1, bottom2)
top = min(top1, top2)
left = right_most(left1, left2)
etc...
Related
Given a list of points forming a polygonal line, and both height and width of a rectangle, how can I find the number and positions of all rectangles needed to cover all the points?
The rectangles should be rotated and may overlap, but must follow the path of the polyline (A rectangle may contain multiple segments of the line, but each rectangle must contain a segment that is contiguous with the previous one.)
Do the intersections on the smallest side of the rectangle, when it is possible, would be much appreciated.
All the solutions I found so far were not clean, here is the result I get:
You should see that it gives a good render in near-flat cases, but overlaps too much in big curbs. One rectangle could clearly be removed if the previous were offset.
Actually, I put a rectangle centered at width/2 along the line and rotate it using convex hull and modified rotating calipers algorithms, and reiterate starting at the intersection point of the previous rectangle and the line.
You may observe that I took inspiration from the minimum oriented rectangle bounding box algorithm, for the orientation, but it doesn't include the cutting aspect, nor the fixed size.
Thanks for your help!
I modified k-means to solve this. It's not fast, it's not optimal, it's not guaranteed, but (IMHO) it's a good start.
There are two important modifications:
1- The distance measure
I used a Chebyshev-distance-inspired measure to see how far points are from each rectangle. To find distance from points to each rectangle, first I transformed all points to a new coordinate system, shifted to center of rectangle and rotated to its direction:
Then I used these transformed points to calculate distance:
d = max(2*abs(X)/w, 2*abs(Y)/h);
It will give equal values for all points that have same distance from each side of rectangle. The result will be less than 1.0 for points that lie inside rectangle. Now we can classify points to their closest rectangle.
2- Strategy for updating cluster centers
Each cluster center is a combination of C, center of rectangle, and a, its rotation angle. At each iteration, new set of points are assigned to a cluster. Here we have to find C and a so that rectangle covers maximum possible number of points. I don’t now if there is an analytical solution for that, but I used a statistical approach. I updated the C using weighted average of points, and used direction of first principal component of points to update a. I used results of proposed distance, powered by 500, as weight of each point in weighted average. It moves rectangle towards points that are located outside of it.
How to Find K
Initiate it with 1 and increase it till all distances from points to their corresponding rectangles become less than 1.0, meaning all points are inside a rectangle.
The results
Iterations 0, 10, 20, 30, 40, and 50 of updating cluster centers (rectangles):
Solution for test case 1:
Trying Ks: 2, 4, 6, 8, 10, and 12 for complete coverage:
Solution for test case 2:
P.M: I used parts of Chalous Road as data. It was fun downloading it from Google Maps. The I used technique described here to sample a set of equally spaced points.
It’s a little late and you’ve probably figured this out. But, I was free today and worked on the constraint reflected in your last edit (continuity of segments). As I said before in the comments, I suggest using a greedy algorithm. It’s composed of two parts:
A search algorithm that looks for furthermost point from an initial point (I used binary search algorithm), so that all points between them lie inside a rectangle of given w and h.
A repeated loop that finds best rectangle at each step and advances the initial point.
The pseudo code of them are like these respectively:
function getBestMBR( P, iFirst, w, h )
nP = length(P);
iStart = iFirst;
iEnd = nP;
while iStart <= iEnd
m = floor((iStart + iEnd) / 2);
MBR = getMBR(P[iFirst->m]);
if (MBR.w < w) & (MBR.h < h) {*}
iStart = m + 1;
iLast = m;
bestMBR = MBR;
else
iEnd = m - 1;
end
end
return bestMBR, iLast;
end
function getRectList( P, w, h )
nP = length(P);
rects = [];
iFirst = 1;
iLast = iFirst;
while iLast < nP
[bestMBR, iLast] = getBestMBR(P, iFirst, w, h);
rects.add(bestMBR.x, bestMBR.y, bestMBR.a];
iFirst = iLast;
end
return rects;
Solution for test case 1:
Solution for test case 2:
Just keep in mind that it’s not meant to find the optimal solution, but finds a sub-optimal one in a reasonable time. It’s greedy after all.
Another point is that you can improve this a little in order to decrease number of rectangles. As you can see in the line marked with (*), I kept resulting rectangle in direction of MBR (Minimum Bounding Rectangle), even though you can cover larger MBRs with rectangles of same w and h if you rotate the rectangle. (1) (2)
I have a list of points (pixels) QList<QPoint> that represent a curve looking like a orthogonal polyline.
My task is to split this one to small straight lines (an instance of QList<QLineF>). In order to know the end of a previous subline and beginning of a next subline, I got to know which points are vertexes of polyline, that is, the points where sublines are intersected.
What would be the best way to figure out that some point is a vertex?
I've found the answer by myself. It doesn't seem to be convenient and clear, nevertheless it works out.
QList<QPoint> vertexes;
for (int i = 2; i < points.size(); i++)
{
bool xChanged = points[i-2].x() != points[i].x();
bool yChanged = points[i-2].y() != points[i].y();
if (xChanged && yChanged)
vertexes.append(points[i-1]);
}
vertexes.prepend(points.first());
vertexes.append(points.last());
We check two points every loop iteration - the current point and the point two points ago. If their X and Y aren't equal, it means that curve change its direction and the point between them is a vertex.
Assume we have a 3D grid that spans some 3D space. This grid is made out of cubes, the cubes need not have integer length, they can have any possible floating point length.
Our goal is, given a point and a direction, to check linearly each cube in our path once and exactly once.
So if this was just a regular 3D array and the direction is say in the X direction, starting at position (1,2,0) the algorithm would be:
for(i in number of cubes)
{
grid[1+i][2][0]
}
But of course the origin and the direction are arbitrary and floating point numbers, so it's not as easy as iterating through only one dimension of a 3D array. And the fact the side lengths of the cubes are also arbitrary floats makes it slightly harder as well.
Assume that your cube side lengths are s = (sx, sy, sz), your ray direction is d = (dx, dy, dz), and your starting point is p = (px, py, pz). Then, the ray that you want to traverse is r(t) = p + t * d, where t is an arbitrary positive number.
Let's focus on a single dimension. If you are currently at the lower boundary of a cube, then the step length dt that you need to make on your ray in order to get to the upper boundary of the cube is: dt = s / d. And we can calculate this step length for each of the three dimensions, i.e. dt is also a 3D vector.
Now, the idea is as follows: Find the cell where the ray's starting point lies in and find the parameter values t where the first intersection with the grid occurs per dimension. Then, you can incrementally find the parameter values where you switch from one cube to the next for each dimension. Sort the changes by the respective t value and just iterate.
Some more details:
cell = floor(p - gridLowerBound) / s <-- the / is component-wise division
I will only cover the case where the direction is positive. There are some minor changes if you go in the negative direction but I am sure that you can do these.
Find the first intersections per dimension (nextIntersection is a 3D vector):
nextIntersection = ((cell + (1, 1, 1)) * s - p) / d
And calculate the step length:
dt = s / d
Now, just iterate:
if(nextIntersection.x < nextIntersection.y && nextIntersection.x < nextIntersection.z)
cell.x++
nextIntersection.x += dt.x
else if(nextIntersection.y < nextIntersection.z)
cell.y++
nextIntersection.y += dt.y
else
cell.z++
nextIntersection.z += dt.z
end if
if cell is outside of grid
terminate
I have omitted the case where two or three cells are changed at the same time. The above code will only change one at a time. If you need this, feel free to adapt the code accordingly.
Well if you are working with floats, you can make the equation for the line in direction specifiedd. Which is parameterized by t. Because in between any two floats there is a finite number of points, you can simply check each of these points which cube they are in easily cause you have point (x,y,z) whose components should be in, a respective interval defining a cube.
The issue gets a little bit harder if you consider intervals that are, dense.
The key here is even with floats this is a discrete problem of searching. The fact that the equation of a line between any two points is a discrete set of points means you merely need to check them all to the cube intervals. What's better is there is a symmetry (a line) allowing you to enumerate each point easily with arithmetic expression, one after another for checking.
Also perhaps consider integer case first as it is same but slightly simpler in determining the discrete points as it is a line in Z_2^8?
I need some help with writing this algorithm.
For a given set of lines in space, I am trying to find the accessible volume when the origin (reference point) is 0.5,0.5,0.5. Currently, I do the following:
For each line, calculate the distance to the origin (0.5,0.5,0.5). Then, gather all these perpendicular distance points on all the lines into a list.
Now, I would like to calculate the "interior" (neither the boundary nor the convhull), because I want to evaluate the accessible volume for a ball centered at (0.5,0.5,0.5).
For example I would like to compute with my algorithm the green (internal line) in this simple example:
The configuration:
The closest points from the origin (0.5,0.5,0.5) to the lines
Only the points for whom I want the "internal boundary" be computed. Meaning the shape that bounds all the point either outside of the interior or on its boundary.
Here is the code for which I want something else rather than convhull:
close all
N=30;
S1 = cell(1, N);
for k = 1:N, S1{k} = rand(1, 3); end
S2 = cell(1, N);
for k = 1:N, S2{k} = rand(1, 3); end
M1 = cat(3, S1{:});
M2 = cat(3, S2{:});
M = permute(cat(1, M1, M2), [1, 3, 2]);
figure
plot3(M(:, :, 1), M(:, :, 2), M(:, :, 3))
hold on
[x,y,z] = sphere;
x=x/100;y=y/100;z=z/100;
plot3(x+0.5,y+0.5,z+0.5)
figure
hold on
NearestIntersectionPoints = cell(1,N);
for k = 1:N
tmp1 = M(1,k,:); tmp2 = M(2,k,:);
v1=tmp1(1,:); v2=tmp2(1,:);
[d, intersection] = point_to_line([0.5,0.5,0.5], v1, v2);
[x,y,z] = sphere;
x=x/500;y=y/500;z=z/500;
plot3(x+intersection(1),y+intersection(2),z+intersection(3))
NearestIntersectionPoints{k} = intersection;
end
MHull = cat(3,NearestIntersectionPoints{:});
X=MHull(:,1,:); Y=MHull(:,2,:); Z=MHull(:,3,:);
X=X(:); Y=Y(:); Z=Z(:);
k = boundary(X,Y,Z);
hold on
plot3(X(k),Y(k),Z(k), 'r-*')
function [d,intersection] = point_to_line(pt, v1, v2)
a = v1 - v2;
b = pt - v2;
d = norm(cross(a,b)) / norm(a);
theta = asin(norm(cross(a,b))/(norm(a)*norm(b)));
intersection = v2 + a * cos(theta);
end
I would do it like this:
tetrahedronize your pointcloud
so create a mesh consisting of tetrahedrons where no tetrahedron intersect any other or contain any point in it. I do it like this:
structures
you need list of points,triangles and tetrahedrons. Each triangle need one counter which will tell you if it is used once or twice.
create first tetrahedron
by 4 nested loops through all points and check if formed tetrahedron does not contain any point inside. If not stop as you found your first tetrahedron. This is O(n^5) but as there are a lot of valid tetrahedrons it will never reach such high runtime... Now just add this tetrahedron to triangle and tetrahedron lists.
find next tetrahedron
now loop through all triangles that has been used once. for each form tetrahedron by using those 3 points used by it and find 4th point the same way as in #2. Valid tetrahedron must not contain any points in it and also must not intersect any existing tetrahedron in the list.
To ensure whole volume will be filled without holes you need to prioritize the process by preferring tetrahedrons with more triangles already in list. So first search 4 triangles if no found than 3 etc ...
For each found valid tetrahedron add it to the lists and look again until no valid tetrahedron can be formed ... The whole process is around O(n^2) so be careful with too many points in pointcloud. Also having normals for triangles stored can speed the tests a lot ...
outer boundary
outer boundary consist of triangles in list which have been used just once
interior boundary
interior gap tetrahedrons should be larger than all the others. So check their size against average size and if bigger they are most likely a gap. So group them together to lists. Each gap have only large tetrahedrons and all of them must share at least one face (triangle). Now just count the triangle usage for each group alone and all the triangles used just once will form your gap/hole/interior boundary/mesh.
If your point density is uniform you can adapt this:
Finding holes in 2d point sets?
And create a voxel map of point density... voxels with no density are either gap or outer space. This can be used for faster and better selection of interior tetrahedrons.
If I understand well your question, you want the largest volume inside another volume, without points in common between the two volumes.
The outer volume is built from a subset of the set of points. The obvious solution is to build the inner volume with the rest of points.
A volume from a set of points can be made in several ways. If the volume is not convex, then you need some more info (e.g. minimum angle between faces) because you get starred polytopo or cuasi-convex, or some other shape.
For convex volume I recomend the 3D Delaunay construction, with tetrahedra. The boundary is defined by the faces of "tets" that are not shared with other "tets".
Remove from the full set of points those belonging to the boundary: Each tet in boundary has a fourth point that does not lie on the boundary.
The inner volume is another Delaunay construction. Perhaps you only need the fourth points from the previous boundary-tets.
This is a problem that I meet on Unity3D, but it's actually a request for help for a general graphical algorithm.
I have a set of 3D objects/meshes that form a map. To generalize let's say that they are arrays of 6 numbers: position and size.
I need to create a box that contains all these objects. The box must have the minimum possible volume. To generalize, we can say that also the box will end to be an array of 9 numbers: position, size and rotation.
So at the end I'm talking about a function that takes a set of array[6] and returns an array[9].
The box can be obviously rotated in 3 directions as needed, so it's not just "take the smallest and the biggest x, y and z values".
Probably this question can some how easily resolved with a few trigonometrical functions, but i don't have any idea of how to do it! I only could create something that does that iteratively, but that's not what I want.
A particular case of this problem could be to find the minimum box containing a set of points. Probably this question is easier and some how can be extended to the main problem. Anyway... I can't solve neither this one! :)
Thanks for the help.
You can find the 3d convex hull of all the vertex. Using the points of the convex hull you can form the faces of the convex hull. Then incline one by one all the faces parallel to x-axis. Then find the min x/y/z and max x/y/z along each face rotation.Calculate the volume using min x/y/z and max x/y/z. Find the index corresponding to the minimum volume. Rotate back this volume using the rotation you used for the corresponding face. This problem is similar to the 2d problem of minimum area rectangle. For minimum area rectangle the reference is https://gis.stackexchange.com/questions/22895/how-to-find-the-minimum-area-rectangle-for-given-points
Quick easy way to get the bottom left rear corner of your new box, and the top right forward corner.
Either:
List<GameObjects> gameObjects; // <-- your game objects here
List<Bounds> objectsBounds = gameObjects.Select(item => item.GetComponent<MeshRenderer>().bounds);
Vector3 min = objectsBounds.Min(item => item.min);
Vector3 max = objectsBounds.Max(item => item.max);
Or:
List<GameObjects> gameObjects; // <-- your game objects here
List<Bounds> objectsBounds = gameObjects.Select(item => item.GetComponent<MeshRenderer>().bounds);
Vector3 min = Vector3.one * Single.MaxValue;
Vector3 max = Vector3.one * Single.MinValue;
foreach(Bounds bounds in objectsBounds)
if(bounds.min < min) min = bounds.min;
foreach(Bounds bounds in objectsBounds)
if(bounds.max > max) max = bounds.max;