I'm trying to implement fast voxel traversal algorithm and calculate T and M according to this answer (T is tDelta, M is tMax). All is good if the two components of the direction vector V are positive. But if at least one of them is negative, it's work wrong.
Green point is start, red is end. All seems correct.
And now from bigger to less position.
Traversal method:
private IEnumerable<Vector2> GetCrossedCells(Vector2 pPoint1, Vector2 pPoint2)
{
Vector2 V = pPoint2 - pPoint1; // direction & distance vector
if (V != Vector2.Zero)
{
Vector2 U = Vector2.Normalize(V); // direction unit vector
Vector2 S = new Vector2(Math.Sign(U.X), Math.Sign(U.Y)); // sign vector
Vector2 P = pPoint1; // position
Vector2 G = new Vector2((int) Math.Floor(P.X / CELL_SIZE), (int) Math.Floor(P.Y / CELL_SIZE)); // grid coord
Vector2 T = new Vector2(Math.Abs(CELL_SIZE / U.X), Math.Abs(CELL_SIZE / U.Y));
Vector2 M = new Vector2(
Single.IsInfinity(T.X) ? Single.PositiveInfinity : T.X * (1.0f - (P.X / CELL_SIZE) % 1),
Single.IsInfinity(T.Y) ? Single.PositiveInfinity : T.Y * (1.0f - (P.Y / CELL_SIZE) % 1));
Vector2 D = Vector2.Zero;
bool isCanMoveByX = S.X != 0;
bool isCanMoveByY = S.Y != 0;
while (isCanMoveByX || isCanMoveByY)
{
yield return G;
D = new Vector2(
S.X > 0 ? (float) (Math.Floor(P.X / CELL_SIZE) + 1) * CELL_SIZE - P.X :
S.X < 0 ? (float) (Math.Ceiling(P.X / CELL_SIZE) - 1) * CELL_SIZE - P.X :
0,
S.Y > 0 ? (float) (Math.Floor(P.Y / CELL_SIZE) + 1) * CELL_SIZE - P.Y :
S.Y < 0 ? (float) (Math.Ceiling(P.Y / CELL_SIZE) - 1) * CELL_SIZE - P.Y :
0);
if (Math.Abs(V.X) <= Math.Abs(D.X))
{
D.X = V.X;
isCanMoveByX = false;
}
if (Math.Abs(V.Y) <= Math.Abs(D.Y))
{
D.Y = V.Y;
isCanMoveByY = false;
}
if (M.X <= M.Y)
{
M.X += T.X;
G.X += S.X;
if (isCanMoveByY)
{
D.Y = U.Y / U.X * D.X; // U.X / U.Y = D.X / D.Y => U.X * D.Y = U.Y * D.X
}
}
else
{
M.Y += T.Y;
G.Y += S.Y;
if (isCanMoveByX)
{
D.X = U.X / U.Y * D.Y;
}
}
V -= D;
P += D;
}
}
}
In debug I can see that for example M.Y > M.X when should be the opposite if S.X < 0 or S.Y < 0.
Tell me please what my code work wrong for negative directions?
So, I solve it.
I make code cleaner and problem is gone.
private IEnumerable<Vector2> GetCrossedCells(Vector2 pPoint1, Vector2 pPoint2)
{
if (pPoint1 != pPoint2)
{
Vector2 V = (pPoint2 - pPoint1) / CELL_SIZE; // direction & distance vector
Vector2 U = Vector2.Normalize(V); // direction unit vector
Vector2 S = new Vector2(Math.Sign(U.X), Math.Sign(U.Y)); // sign vector
Vector2 P = pPoint1 / CELL_SIZE; // position in grid coord system
Vector2 G = new Vector2((int) Math.Floor(P.X), (int) Math.Floor(P.Y)); // grid coord
Vector2 T = new Vector2(Math.Abs(CELL_SIZE / U.X), Math.Abs(CELL_SIZE / U.Y));
Vector2 D = new Vector2(
S.X > 0 ? 1 - P.X % 1 : S.X < 0 ? P.X % 1 : 0,
S.Y > 0 ? 1 - P.Y % 1 : S.Y < 0 ? P.Y % 1 : 0);
Vector2 M = new Vector2(
Single.IsInfinity(T.X) || S.X == 0 ? Single.PositiveInfinity : T.X * D.X,
Single.IsInfinity(T.Y) || S.Y == 0 ? Single.PositiveInfinity : T.Y * D.Y);
bool isCanMoveByX = S.X != 0;
bool isCanMoveByY = S.Y != 0;
while (isCanMoveByX || isCanMoveByY)
{
yield return G;
D = new Vector2(
S.X > 0 ? (float) Math.Floor(P.X) + 1 - P.X :
S.X < 0 ? (float) Math.Ceiling(P.X) - 1 - P.X :
0,
S.Y > 0 ? (float) Math.Floor(P.Y) + 1 - P.Y :
S.Y < 0 ? (float) Math.Ceiling(P.Y) - 1 - P.Y :
0);
if (Math.Abs(V.X) <= Math.Abs(D.X))
{
D.X = V.X;
isCanMoveByX = false;
}
if (Math.Abs(V.Y) <= Math.Abs(D.Y))
{
D.Y = V.Y;
isCanMoveByY = false;
}
if (M.X <= M.Y)
{
M.X += T.X;
G.X += S.X;
if (isCanMoveByY)
{
D.Y = U.Y / U.X * D.X; // U.X / U.Y = D.X / D.Y => U.X * D.Y = U.Y * D.X
}
}
else
{
M.Y += T.Y;
G.Y += S.Y;
if (isCanMoveByX)
{
D.X = U.X / U.Y * D.Y;
}
}
V -= D;
P += D;
}
}
}
Update
I'm began from removing redundant divisions on GRID_CELL and then notice mistake in M calculation.
There are using Frac() function in answer to the question, a link to which I provided. I'm calculate it like (1 - P % 1), but that is a case for S > 0, and there are should be (P % 1) if S < 0, and Inf for S = 0.
Update 2
Also there should be
Vector2 D = new Vector2(
S.X > 0 ? (float) Math.Floor(P.X) + 1 - P.X :
S.X < 0 ? (float) Math.Ceiling(P.X) - 1 - P.X :
0,
S.Y > 0 ? (float) Math.Floor(P.Y) + 1 - P.Y :
S.Y < 0 ? (float) Math.Ceiling(P.Y) - 1 - P.Y :
0);
Instead of
Vector2 D = new Vector2(
S.X > 0 ? 1 - P.X % 1 : S.X < 0 ? P.X % 1 : 0,
S.Y > 0 ? 1 - P.Y % 1 : S.Y < 0 ? P.Y % 1 : 0);
Because M will be infinity in case S < 0 and P haven't fractional part.
Related
I use quaternion from CMAttitude to rotate SceneKit camera.
Also I need to use Y rotation angle extracted from the quaternion.
I expected that it would be roll, but after extraction Y rotation angle corresponds to the pitch which has -90:90 range.
How can I convert this range to 0:180 or 0:360?
- (SCNQuaternion)SCNQuaternionFromCMQuaternion:(CMQuaternion)q {
GLKQuaternion Q = GLKQuaternionMake(q.x, q.y, q.z, q.w);
GLKQuaternion xRotQ = GLKQuaternionMakeWithAngleAndAxis(-M_PI_2, 1, 0, 0);
Q = GLKQuaternionMultiply(xRotQ, Q);
double roll = atan2(2.0 * (Q.y * Q.z - Q.w * Q.x), 1.0 - 2.0 * (Q.x * Q.x + Q.y * Q.y)); // 0:180 but around X
double pitch = RADIANS_TO_DEGREES(asin(-2.0f * (Q.x * Q.z + Q.w * Q.y))); // 0:90 around Y
NSLog(#"%f", pitch);
// ...
CMQuaternion rq = {.x = Q.x, .y = Q.y, .z = Q.z, .w = Q.w};
return SCNVector4Make(rq.x, rq.y, rq.z, rq.w);
}
I found this way:
- (SCNQuaternion)SCNQuaternionFromCMQuaternion:(CMQuaternion)q {
GLKQuaternion Q = GLKQuaternionMake(q.x, q.y, q.z, q.w);
GLKQuaternion xRotQ = GLKQuaternionMakeWithAngleAndAxis(-M_PI_2, 1, 0, 0);
Q = GLKQuaternionMultiply(xRotQ, Q);
double gx = 2.0 * (Q.y * Q.w - Q.x * Q.z);
//double gy = 2.0 * (Q.x * Q.y + Q.z * Q.w);
double gz = Q.x * Q.x - Q.y * Q.y - Q.z * Q.z + Q.w * Q.w;
double pitch = RADIANS_TO_DEGREES(-asin( -2.0 * (Q.y * Q.w - Q.x * Q.z)));
if (gx >= 0 && gz < 0)
pitch = 180 - pitch;
else if (gx < 0 && gz < 0)
pitch = 180 - pitch;
else if (gx < 0 && gz >= 0)
pitch = 360 + pitch;
NSLog(#"%f", pitch); // now it has 0-360 range
CMQuaternion rq = {.x = Q.x, .y = Q.y, .z = Q.z, .w = Q.w};
return SCNVector4Make(rq.x, rq.y, rq.z, rq.w);
}
I have an Array of CGPoints and I would like to find those points, which build a shape. Please see the attached image:
The red circles just mark the points I have.
How can the area with the question mark be found?
Thanks.
You are going to have to start with your first line segment and check for intersections. Obviously if the first two line segments intersect then they are the same line and your shape is just a line, so ignore that case. As you continue down your line segments once you find a segment pair that intersect then you have your shape.
Check line segment 2 against line segment 1. Then check line segment 3 against line segment 2, then against line segment 1. Then check 4 against 3, then 2, then 1, etc... If you find that line segment 7 intersects with line segment 3, delete the first point of line segment 3 and se it to the intersection point you found. Then delete the last point of line segment 7 and set it to the intersection point you found. There you have your shape.
Here is an example method to find the intersection of 2 line segments (written in C#, but it's straight math so it should be very easy to convert to any language you would like). Taken from here:
// Determines if the lines AB and CD intersect.
static bool LinesIntersect(PointF A, PointF B, PointF C, PointF D)
{
PointF CmP = new PointF(C.X - A.X, C.Y - A.Y);
PointF r = new PointF(B.X - A.X, B.Y - A.Y);
PointF s = new PointF(D.X - C.X, D.Y - C.Y);
float CmPxr = CmP.X * r.Y - CmP.Y * r.X;
float CmPxs = CmP.X * s.Y - CmP.Y * s.X;
float rxs = r.X * s.Y - r.Y * s.X;
if (CmPxr == 0f)
{
// Lines are collinear, and so intersect if they have any overlap
return ((C.X - A.X < 0f) != (C.X - B.X < 0f))
|| ((C.Y - A.Y < 0f) != (C.Y - B.Y < 0f));
}
if (rxs == 0f)
return false; // Lines are parallel.
float rxsr = 1f / rxs;
float t = CmPxs * rxsr;
float u = CmPxr * rxsr;
return (t >= 0f) && (t <= 1f) && (u >= 0f) && (u <= 1f);
}
I've figured out the solution.
This function returns a polygon for each area that gets closed by intersecting lines.
func intersectionOfLineFrom(p1: CGPoint, to p2: CGPoint, withLineFrom p3: CGPoint, to p4: CGPoint) -> NSValue? {
let d: CGFloat = (p2.x - p1.x) * (p4.y - p3.y) - (p2.y - p1.y) * (p4.x - p3.x)
if d == 0 {
return nil
}
// parallel lines
let u: CGFloat = ((p3.x - p1.x) * (p4.y - p3.y) - (p3.y - p1.y) * (p4.x - p3.x)) / d
let v: CGFloat = ((p3.x - p1.x) * (p2.y - p1.y) - (p3.y - p1.y) * (p2.x - p1.x)) / d
if u < 0.0 || u > 1.0 {
return nil
}
// intersection point not between p1 and p2
if v < 0.0 || v > 1.0 {
return nil
}
// intersection point not between p3 and p4
var intersection: CGPoint = CGPointZero
intersection.x = p1.x + u * (p2.x - p1.x)
intersection.y = p1.y + u * (p2.y - p1.y)
return NSValue(CGPoint: intersection)
}
func intersectedPolygons(points: [CGPoint]) -> [[CGPoint]] {
var removeIndexBelow : Int = 0
var removeIndexAbove : Int = 0
var resultArrays : [[CGPoint]] = [[CGPoint]]()
for i in 1..<points.count {
let firstLineStart = points[i-1] as CGPoint
let firstLineEnd = points[i] as CGPoint
for var j = points.count-1; j > i+1; j-- {
let lastLineStart = points[j-1] as CGPoint
let lastLineEnd = points[j] as CGPoint
if let intersect: NSValue = self.intersectionOfLineFrom(firstLineStart, to: firstLineEnd, withLineFrom: lastLineStart, to: lastLineEnd){
var pointsCopy = points
let intersection = intersect.CGPointValue()
pointsCopy[i-1] = intersection
pointsCopy[j] = intersection
removeIndexBelow = i
removeIndexAbove = j
let fullPoly = Array(pointsCopy[removeIndexBelow-1..<removeIndexAbove])
resultArrays.append(fullPoly)
break;
}
}
}
return resultArrays
}
My question is how to color disparity maps like this page: http://vision.middlebury.edu/stereo/data/scenes2014/.
Thank you in advance for any suggestions.
Those Disparity map is created using the depth information and u can color the depth map using axis direction.
Also you can create your own method by Building a JetColor Map.
template<typename T, typename U, typename V>
inline cv::Scalar cvJetColourMat(T v, U vmin, V vmax) {
cv::Scalar c = cv::Scalar(1.0, 1.0, 1.0); // white
T dv;
if (v < vmin)
v = vmin;
if (v > vmax)
v = vmax;
dv = vmax - vmin;
if (v < (vmin + 0.25 * dv)) {
c.val[0] = 0;
c.val[1] = 4 * (v - vmin) / dv;
} else if (v < (vmin + 0.5 * dv)) {
c.val[0] = 0;
c.val[2] = 1 + 4 * (vmin + 0.25 * dv - v) / dv;
} else if (v < (vmin + 0.75 * dv)) {
c.val[0] = 4 * (v - vmin - 0.5 * dv) / dv;
c.val[2] = 0;
} else {
c.val[1] = 1 + 4 * (vmin + 0.75 * dv - v) / dv;
c.val[2] = 0;
}
return(c);
}
Note that you can change to other color components incase you need it.
What I was thinking to do is to convert ofColor to l*a*b color space and measure the euclidean distance. But I don't know how should I do it in openframeworks?
I'm not very experienced with c++ but I ported this snippet over:
//ported from http://cookbooks.adobe.com/post_Useful_color_equations__RGB_to_LAB_converter-14227.html
struct Color{
float R,G,B,X,Y,Z,L,a,b;
};
#define REF_X 95.047; // Observer= 2°, Illuminant= D65
#define REF_Y 100.000;
#define REF_Z 108.883;
Color rgb2xyz(int R,int G,int B){
float r = R / 255.0;
float g = G / 255.0;
float b = B / 255.0;
if (r > 0.04045){ r = pow((r + 0.055) / 1.055, 2.4); }
else { r = r / 12.92; }
if ( g > 0.04045){ g = pow((g + 0.055) / 1.055, 2.4); }
else { g = g / 12.92; }
if (b > 0.04045){ b = pow((b + 0.055) / 1.055, 2.4); }
else { b = b / 12.92; }
r = r * 100;
g = g * 100;
b = b * 100;
//Observer. = 2°, Illuminant = D65
Color xyz;
xyz.X = r * 0.4124 + g * 0.3576 + b * 0.1805;
xyz.Y = r * 0.2126 + g * 0.7152 + b * 0.0722;
xyz.Z = r * 0.0193 + g * 0.1192 + b * 0.9505;
return xyz;
}
Color xyz2lab(float X,float Y, float Z){
float x = X / REF_X;
float y = Y / REF_X;
float z = Z / REF_X;
if ( x > 0.008856 ) { x = pow( x , .3333333333f ); }
else { x = ( 7.787 * x ) + ( 16/116.0 ); }
if ( y > 0.008856 ) { y = pow( y , .3333333333f ); }
else { y = ( 7.787 * y ) + ( 16/116.0 ); }
if ( z > 0.008856 ) { z = pow( z , .3333333333f ); }
else { z = ( 7.787 * z ) + ( 16/116.0 ); }
Color lab;
lab.L = ( 116 * y ) - 16;
lab.a = 500 * ( x - y );
lab.b = 200 * ( y - z );
return lab;
}
Color lab2xyz(float l, float a, float b){
float y = (l + 16) / 116;
float x = a / 500 + y;
float z = y - b / 200;
if ( pow( y , 3 ) > 0.008856 ) { y = pow( y , 3 ); }
else { y = ( y - 16 / 116 ) / 7.787; }
if ( pow( x , 3 ) > 0.008856 ) { x = pow( x , 3 ); }
else { x = ( x - 16 / 116 ) / 7.787; }
if ( pow( z , 3 ) > 0.008856 ) { z = pow( z , 3 ); }
else { z = ( z - 16 / 116 ) / 7.787; }
Color xyz;
xyz.X = x * REF_X;
xyz.Y = y * REF_Y;
xyz.Z = z * REF_Z;
return xyz;
}
Color xyz2rgb(float X,float Y,float Z){
//X from 0 to 95.047 (Observer = 2°, Illuminant = D65)
//Y from 0 to 100.000
//Z from 0 to 108.883
X = ofClamp(X, 0, 95.047);
float x = X * .01;
float y = Y * .01;
float z = Z * .01;
float r = x * 3.2406 + y * -1.5372 + z * -0.4986;
float g = x * -0.9689 + y * 1.8758 + z * 0.0415;
float b = x * 0.0557 + y * -0.2040 + z * 1.0570;
if ( r > 0.0031308 ) { r = 1.055 * pow( r , ( 1 / 2.4f ) ) - 0.055; }
else { r = 12.92 * r; }
if ( g > 0.0031308 ) { g = 1.055 * pow( g , ( 1 / 2.4f ) ) - 0.055; }
else { g = 12.92 * g; }
if ( b > 0.0031308 ) { b = 1.055 * pow( b , ( 1 / 2.4f ) ) - 0.055; }
else { b = 12.92 * b; }
Color rgb;
rgb.R = round( r * 255 );
rgb.G = round( g * 255 );
rgb.B = round( b * 255 );
return rgb;
}
Color rgb2lab(int R,int G,int B){
Color xyz = rgb2xyz(R, G, B);
return xyz2lab(xyz.X, xyz.Y, xyz.Z);
}
Color lab2rgb(int L,int a,int b){
Color xyz = lab2xyz(L, a, b);
return xyz2rgb(xyz.X, xyz.Y, xyz.Z);
}
Measuring the distance would be something as trivial as:
float distLab(Color c1,Color c2){
float dL = c1.L - c2.L;
float da = c1.a - c2.a;
float db = c1.b - c2.b;
return sqrt(dL*dL + da*da + db*db);
}
or ofVec3f(c1.L,c1.a,c1.b).distance(ofVec3f(c2.L,c2.a,c2.b));
Also see this answer for an openframeworks basic example.
I have this class for AABB wich i foun in internet and it have worked for when mesh moves, but when i rotate mesh of course it stops working, also i have noted that it has a transform function so i think this is what i have to use so it works after i rotate the mesh, but im a little bit new with matrix and i don't know how to use it:
#ifndef AABB_H
#define AABB_H
class aabb {
public:
aabb() { min.x = min.y = min.z = 1e24f; max.x = max.y = max.z = -1e24f; }
aabb &operator =(const aabb &a) { min = a.min; max = a.max; return *this; }
vec3d min, max;
vec3d center() { return ((min + max) * 0.5f); }
void empty() { min.x = min.y = min.z = 1e24f; max.x = max.y = max.z = -1e24f; }
void add(const vec3d &pnt) {
if (pnt.x < min.x) min.x = pnt.x;
if (pnt.x > max.x) max.x = pnt.x;
if (pnt.y < min.y) min.y = pnt.y;
if (pnt.y > max.y) max.y = pnt.y;
if (pnt.z < min.z) min.z = pnt.z;
if (pnt.z > max.z) max.z = pnt.z;
}
void transform(const mat3x3 &m, const vec3d &trans) {
vec3d oldmin = min, oldmax = max;
min = max = trans;
if (m.m11 > 0.0f) { min.x += m.m11 * oldmin.x; max.x += m.m11 * oldmax.x; }
else { min.x += m.m11 * oldmax.x; max.x += m.m11 * oldmin.x; }
if (m.m12 > 0.0f) { min.y += m.m21 * oldmin.x; max.y += m.m21 * oldmax.x; }
else { min.y += m.m21 * oldmax.x; max.y += m.m21 * oldmin.x; }
if (m.m13 > 0.0f) { min.z += m.m31 * oldmin.x; max.z += m.m31 * oldmax.x; }
else { min.z += m.m31 * oldmax.x; max.z += m.m31 * oldmin.x; }
if (m.m21 > 0.0f) { min.x += m.m12 * oldmin.y; max.x += m.m12 * oldmax.y; }
else { min.x += m.m12 * oldmax.y; max.x += m.m12 * oldmin.y; }
if (m.m22 > 0.0f) { min.y += m.m22 * oldmin.y; max.y += m.m22 * oldmax.y; }
else { min.y += m.m22 * oldmax.y; max.y += m.m22 * oldmin.y; }
if (m.m23 > 0.0f) { min.z += m.m32 * oldmin.y; max.z += m.m32 * oldmax.y; }
else { min.z += m.m32 * oldmax.y; max.z += m.m32 * oldmin.y; }
if (m.m31 > 0.0f) { min.x += m.m13 * oldmin.z; max.x += m.m13 * oldmax.z; }
else { min.x += m.m13 * oldmax.z; max.x += m.m13 * oldmin.z; }
if (m.m32 > 0.0f) { min.y += m.m23 * oldmin.z; max.y += m.m23 * oldmax.z; }
else { min.y += m.m23 * oldmax.z; max.y += m.m23 * oldmin.z; }
if (m.m33 > 0.0f) { min.z += m.m33 * oldmin.z; max.z += m.m33 * oldmax.z; }
else { min.z += m.m33 * oldmax.z; max.z += m.m33 * oldmin.z; }
}
bool contains(const vec3d &a) { return (a.x >= min.x) && (a.x <= max.x) && (a.y >= min.y) && (a.y <= max.y) && (a.z >= min.z) && (a.z <= max.z); }
vec3d closest(const vec3d &a) {
vec3d r;
if (a.x < min.x) r.x = min.x;
else if (a.x > max.x) r.x = max.x;
else r.x = a.x;
if (a.y < min.y) r.y = min.y;
else if (a.y > max.y) r.y = max.y;
else r.y = a.y;
if (a.z < min.z) r.z = min.z;
else if (a.z > max.z) r.z = max.z;
else r.z = a.z;
return r;
}
};
#endif
Also as aditional data i just want to rotate mesh in Y-axix because it's a naval game.
Thanks for answers.
I recognize that code from the book 3d math primer for graphics and game development, but it's not exactly the same. I can see that the translation part would work but not any rotation. The trans is meant to be the translation part of your matrix. In the book, a bounding box is passed in as well to the method. In the code you have found, this is removed an replaced with saving the old min and max values to start with in the method. The code will expand the min and max values to infinity (just adding on and on and on). The code is optimized so that not all 8 corner points are transformed but instead utilizing how a point is transformed by a matrix and figuring out which one of these would have the smallest value after the transformation. The trick to minimize the entire sum is to minimize each of the products individually for each of the 9 elements in the matrix.
Something like this works for me...
public void add(float[] p) {
if (p[0] < mOriginalMin[0]) {
mOriginalMin[0] = p[0];
}
if (p[0] > mOriginalMax[0]) {
mOriginalMax[0] = p[0];
}
if (p[1] < mOriginalMin[1]) {
mOriginalMin[1] = p[1];
}
if (p[1] > mOriginalMax[1]) {
mOriginalMax[1] = p[1];
}
if (p[2] < mOriginalMin[2]) {
mOriginalMin[2] = p[2];
}
if (p[2] > mOriginalMax[2]) {
mOriginalMax[2] = p[2];
}
}
public void transform(Matrix44 mat) {
/** Get the translation part */
mCurrMin[0] = mCurrMax[0] = mat.m[12];
mCurrMin[1] = mCurrMax[1] = mat.m[13];
mCurrMin[2] = mCurrMax[2] = mat.m[14];
if (mat.m[0] > 0) {
mCurrMin[0] += mat.m[0] * mOriginalMin[0];
mCurrMax[0] += mat.m[0] * mOriginalMax[0];
} else {
mCurrMin[0] += mat.m[0] * mOriginalMax[0];
mCurrMax[0] += mat.m[0] * mOriginalMin[0];
}
.....etc etc.
I think that 'trans' means translate not transform (hint: there are no matrix operations being performed here). Speaking of transforms and matrices - there is your answer. If the object is rotated, translated, or scaled then you should get its global (world) matrix and multiply the min and max by it. Then recalculate your center.