How to access min and max coordinates of a 3D object in C++? - c++

I am creating a game in qt Creator using c++ and OpenGL and an attempting to add bounding boxes to my scene in order to implement collision detection. I am using objects imported from Maya as .obj in my scene so their dimensions are not set in the code, only their position, rotation and scale. I am able to create a bounding box around each object which matches their position but am struggling to find a way to access the min and max x, y and z values of the objects in order to match the box to the size of the object.
Does anyone have any ideas on how I could access the min and max coordinates? I know how to implement the code if I could access these values..

The problem you afford is that each object geometry has different means of internal storage and determination of a bounding box.
Let's try some examples to illustrate this:
Suppose we have a circle, whose drawing parameters stored internally are the center coordinates x_center and y_center and the radius radius. If you try to determine the bounding box for this object, you'll see that it extends from (x_center - radius, y_center - radius) to (x_center + radius, y_center + radius).
In case you have an unrotated rectangle, given by the two points of it's principal diagonal, the bounding box just coincides with it's shape, so you have only to give the coordinates of the two same points that represent it.
If, on the other way, we have a polygon, the bounding box will be determined by the minimum and maximum coordinates of all the polygon vertices. If you allow to rotate the polygon, you'll need to rotate all the vertices coordinates before determining their maximum and minimum values, to get the bounding box.
If, for another example, we have a cubic spline, determined by the coordinates of its four control points you'll be determining the maximum and minimum values of two cubic polygons, which means solving two quadratic equations(after derivation), in the general case.
To cope with all this stuff, a geometric shape normally includes some means of polymorphically construct it's bounding box (it normally is even cached, so you don't have to calculate it, only after rotations or variations in it's position or scale) via some instance method.
Of course, all of this depends on how and how has defined the way shapes are implemented. perhaps your case is simpler than I'm exposing here, but you don't say. You also don't show any code or input/output data, as stated in the How to create a Minimal, Complete, and Verifiable example page. So you had better to edit your question and add your sample code, that will show more information about your exact problem.

if you have obj loader so you have an array.
float t[2100];
int x = 2100;
float xmax=-123243;
while(x>=0)
{
if(xmax<t[x]) xmax=t[x];
x-=3;
}
So here is a maximum x of the object(?).

Related

Axis-Aligned Bounding Box Calculation (AABB) for different orientations of 3D object

I am trying to calculate the Axis-Aligned Bounding Box of a 3d CAD model (.stp file) for different orientations.
More specifically, imagine a 3d object lying on a virtual workbench and we have a top view of it in a CAD program.
We only care about the top view (representing the projection of the object on the XY plane).
The final goal is to create a table containing the ratio of the bounding box X and Y sides for every degree of rotation.
Τhe following sketches clarify what I mean.
Any ideas/ suggestions for any part of the task?
I've got two ideas for solution approaches. (depending of the capability of your cad software)
Using kind of "extreme point" function. Get the coordinates of these extreme points by varying the direction the point is generated
Create a straight line (or plane in 3d) which does not intersect your geometry. Measure the minimal distance between your body an the line/plane. Rotate the line/plane around your body (around the cog) stepwise to get multiple measurements.

How to check if two rectangles, one is rotated, intersect in SFML

I have a rotated Rectangle inside a closed tile map of rectangles.
What would be the best way to check if the player (which is the rotated rectangle) is intersecting with one of the rectangles of the tile map?
Picture from inside the game to better show what the map looks like:
If it matters, the Player's type is sf::Shape and the map's data is inside an int array.
SFML does not provide collision detection, it only has method to check if two axis-aligned rectangles intersect. If you need something more complex, you will have to implement if yourself.
If you don't need precision detection, you can test Sprite.getGlobalBounds().intersects(...) with the rectangle of the map.
If you want ideal collision detection, you have more then one option:
Pixel perfect Collision. First check if bounding box intersect the map tile and them check all non-transparent pixels for collision. Not very fast but easy to implement and may be suitable for your case.
Mathematical methods, there are more that one, but take a look at Separating Axis Theorem. If your are only limited to rectangles (or/and circles and convex polygons), it will work best.
For anyone still having this issue:
You should look into the getTransform() and getInverseTransform() functions of sf::Transformable (https://www.sfmldev.org/documentation/2.5.1/classsf_1_1Transformable.php). Getting the inverse transforms of the player and a specific wall allows you to use a simple AABB collision algorithm (like SFML already implemented it in getGlobalBounds().intersects(...)). You basicly look at the local coordinate system of the player and how the wall is positioned to it, all translations, rotations and scaling ignored.

Draping 2d point on a 3d terrain

I am using OpenTK(OpenGL) and a general hint will be helpful.
I have a 3d terrain. I have one point on this terrain O(x,y,z) and two perpendicular lines passing through this point that will serve as my X and Y axes.
Now I have a set of 2d points with are in polar coordinates (range,theta). I need to find which points on the terrain correspond to these points. I am not sure what is the best way to do it. I can think of two ideas:
Lets say I am drawing A(x1,y1).
Find the intersection of plane passing through O and A which is perpendicular to the XY plane. This will give me a polyline (semantics may be off). Now on this line, I find a point that is visible from O and is at a distance of the range.
Create a circle which is perpendicular to the XY plane with radius "range", find intersection points on the terrain, find which ones are visible from O and drop rest.
I understand I can find several points which satisfy the conditions, so I will do further check based on topography, but for now I need to get a smaller set which satisfy this condition.
I am new to opengl, but I get geometry pretty well. I am wondering if something like this exists in opengl since it is a standard problem with ground measuring systems.
As you say, both of the options you present will give you more than the one point you need. As I understand your problem, you need only to perform a change of bases from polar coordinates (r, angle) to cartesian coordinates (x,y).
This is fairly straight forward to do. Assuming that the two coordinate spaces share the origin O and that the angle is measured from the x-axis, then point (r_i, angle_i) maps to x_i = r_i*cos(angle_i) and y_i = r_i*sin(angle_i). If those assumptions aren't correct (i.e. if the origins aren't coincident or the angle is not measured from a radii parallel to the x-axis), then the transformation is a bit more complicated but can still be done.
If your terrain is represented as a height map, or 2D array of heights (e.g. Terrain[x][y] = z), once you have the point in cartesian coordinates (x_i,y_i) you can find the height at that point. Of course (x_i, y_i) might not be exactly one of the [x] or [y] indices of the height map.
In that case, I think you have a few options:
Choose the closest (x,y) point and take that height; or
Interpolate the height at (x_i,y_i) based on the surrounding points in the height map.
Unfortunately I am also learning OpenGL and can not provide any specific insights there, but I hope this helps solve your problem.
Reading your description I see a bit of confusion... maybe.
You have defined point O(x,y,z). Fine, this is your pole for the 3D coordinate system. Then you want to find a point defined by polar coordinates. That's fine also - it gives you 2D location. Basically all you need to do is to pinpoint the location in 3D A'(x,y,0), because we are assuming you know the elevation of the A at (r,t), which you of course do from the terrain there.
Angle (t) can be measured only from one axis. Choose which axis will be your polar north and stick to. Then you measure r you have and - voila! - you have your location. What's the point of having 2D coordinate set if you don't use it? Instead, you're adding visibility to the mix - I assume it is important, but highest terrain point on azimuth (t) NOT NECESSARILY will be in the range (r).
You have specific coordinates. Just like RonL suggest, convert to (x,y), find (z) from actual terrain and be done with it.
Unless that's not what you need. But in that case a different question is in order: what do you look for?

Determine if point is inside boost::geometry::linear_ring accounting orientation

I want to determine if point is inside polygon with boost::geometry.
I use function boost::geometry::within and type boost::geometry::linear_ring<boost::geometry::point_2d> to specify contour.
All work fine if I don't need to account orientation of contour.
But in my case I want to account orientation. I mean that if inner region for specific contour is considered limited by its border and finite, then the inner area of inverted contour should be infinite - complementation to area of initial contour.
Is it possible to account orientation of contour in within function?
It can be expessed in the following code:
// Create contour which defines square
boost::geometry::linear_ring<boost::geometry::point_2d> contour;
contour.push_back(boost::geometry::point_2d(4, 2));
contour.push_back(boost::geometry::point_2d(2, 2));
contour.push_back(boost::geometry::point_2d(2, 4));
contour.push_back(boost::geometry::point_2d(4, 4));
contour.push_back(boost::geometry::point_2d(4, 2));
// Create contour which defines square with opposite direction.
boost::geometry::linear_ring<boost::geometry::point_2d> contourInverted = contour;
std::reverse(contourInverted.begin(), contourInverted.end());
// Specify point inside square
boost::geometry::point_2d testPoint(3, 3);
// Perform tests
bool ret1 = boost::geometry::within(testPoint, contour);
bool ret2 = boost::geometry::within(testPoint, contourInverted);
After execution of the code above ret1 and ret2 are both true. But I would have ret1 != ret2.
In general I need to obtain functionaly when ret1 != ret2 for any testPoint (I don't consider border cases here when point is exactly on the border or polygon is degenerated etc...)
I tried different strategies to pass to boost::geometry::within, but I have not obtained what I need.
It seems that functionality which I need or similar is implemented somewhere in the boost::geometry, because the documetation for within has example of polygon with holes. But I have not realised how to use it for my case.
There is also quite simple workaround. I need just write a code to determine orientation of contour. Then I just negate or not result of within function depending on contour orientation. But if boost::geometry has implementation already I don't want to duplicate it.
AFAIK, neither Boost.Geometry nor Boost.Polygon work with "infinite" areas you defined. They do work with polygon with holes and even sets of such polygons.
You might consider adding a big rectangle limiting your universe. Then you can define inverted contour as a hole in such rectangle.
BTW, in many cases one can avoid converting box to a contour. Boost.Geometry provides an adapter "box_view" which allows to use box as if it were a (positively oriented) contour.
As for orientation of an arbitrary contour, probably the easiest way is to compute its area. On the other side, for well-formed ring the orientation is known at compile-time and is provided by meta-functions traits::point_order, see details here
A few remarks:
In Boost.Geometry there is no bg::linear_ring<>, there is bg::model::ring<>.
bg::model::ring<> is a model of what in Boost.Geometry is called a Ring which is an areal geometry, a simple Polygon without holes.
Ring differs from OGC LinearRing, it's an areal (2d) geometry and it has an orientation. OGC LinearRing is 1d with no orientation.
It's possible to set an orientation of bg::model::ring<> in compile-time by passing the 2nd template parameter, see this.
a value returned by the area() function for a reversed areal (cartesian) geometry is a negative area (not infinite). But not all functions works for reversed geometries because the library considers them as invalid in general.
In Boost.Geometry the data must reflect the compile-time setup of a geometry, in this case the orientation set for the Ring at compile-time. Otherwise the results may be unexpected. In your case the same value is returned. You can call bg::correct() to automatically correct the orientation and closure before passing the geometry to other functions. You can also call bg::is_valid() to check if everything is ok with your geometry.
So if you want to check if a point overlaps an interior of a geometry you can call within(pt, ring). And if you want to check if a point is on the boundary or overlapping the exterior then !within(pt, ring) should return what you need, which is of course obvious.
If you wanted to take the boundary into account so check if a point overlaps the interior or boundary then you could use covered_by(pt, ring), !disjoint(pt, ring) or intersects(pt, ring). Obviously, the complement in this case could be !covered_by(pt, ring), disjoint(pt, ring) or !intersects(pt, ring).
In the case of Pt/Ring, internally the same code is used to check all of those spatial relations so it shouldn't matter which one is called.

Fit a circle or a spline into a bunch of 3D Points

I have some 3D Points that roughly, but clearly form a segment of a circle. I now have to determine the circle that fits best all the points. I think there has to be some sort of least squares best fit but I cant figure out how to start.
The points are sorted the way they would be situated on the circle. I also have an estimated curvature at each point.
I need the radius and the plane of the circle.
I have to work in c/c++ or use an extern script.
You could use a Principal Component Analysis (PCA) to map your coordinates from three dimensions down to two dimensions.
Compute the PCA and project your data onto the first to principal components. You can then use any 2D algorithm to find the centre of the circle and its radius. Once these have been found/fitted, you can project the centre back into 3D coordinates.
Since your data is noisy, there will still be some data in the third dimension you squeezed out, but bear in mind that the PCA chooses this dimension such as to minimize the amount of data lost, i.e. by maximizing the amount of data that is represented in the first two components, so you should be safe.
A good algorithm for such data fitting is RANSAC (Random sample consensus). You can find a good description in the link so this is just a short outline of the important parts:
In your special case the model would be the 3D circle. To build this up pick three random non-colinear points from your set, compute the hyperplane they are embedded in (cross product), project the random points to the plane and then apply the usual 2D circle fitting. With this you get the circle center, radius and the hyperplane equation. Now it's easy to check the support by each of the remaining points. The support may be expressed as the distance from the circle that consists of two parts: The orthogonal distance from the plane and the distance from the circle boundary inside the plane.
Edit:
The reason because i would prefer RANSAC over ordinary Least-Squares(LS) is its superior stability in the case of heavy outliers. The following image is showing an example comparision of LS vs. RANSAC. While the ideal model line is created by RANSAC the dashed line is created by LS.
The arguably easiest algorithm is called Least-Square Curve Fitting.
You may want to check the math,
or look at similar questions, such as polynomial least squares for image curve fitting
However I'd rather use a library for doing it.