darkprinze's picture

Measure bounding box edges

I created a bounding box for mesh model but i have to measure different edges. I need to find where points touching the box and calculate distance from those points. Its kinda hard to explain the requirement so i have attached the image which gives the better explanation. I have all values (min_x, max_x, min_y, max_y, min_z, max_z) to calculate the different edges. I used the following formula to calculate size, center and bounding box distance.

size = new Vector3(max_x - min_x, max_y - min_y, max_z - min_z);
center = new Vector3((min_x + max_x) / 2, (min_y + max_y) / 2, (min_z + max_z) / 2);
 
 float[] min = new float[3] { min_x, min_y, min_z };
 float[] max = new float[3] { max_x, max_y, max_z };
 dist = (float)Math.Sqrt(min.Zip(max, (a, b) => (a - b) * (a - b)).Sum());

Now, i need to measure the values as explained in picture. It would be great if someone provide the formula or hint.

Inline Images

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
winterhell's picture

If you simply want the extreme points of the object in all 3 axis, then here is a way. You'll get 6 points, that are the lowest and highest on their respective axis. There could be more than 1 point fulfilling the requirement, but this will get you the first or last of them depending on how you configure the code.

Vector3 minX,maxX,minY,maxY,minZ,maxZ;
Vector3 vertices;//this is your array of vertices
minX=maxX=minY=maxY=minZ=maxZ=vertices[0];
for(int i=1;i<vertices.Length;i++)//i could start at 0 as well, doesnt make a difference
{
if(vertices[i].X<minX.X) minX=vertices[i];
if(vertices[i].X>maxX.X)maxX=vertices[i];
//etc for Y and Z
}

Not all of the 6 points would be touching the bounding box, but will be the southest one/northest one/east one/most north one/top one/bottom one.
If you wish you can do this in the loop that calculates the bounding box. Calculating those points however does not require having/calculating a bounding box.

darkprinze's picture

Thank you for the reply. I already have all six values (min_x, max_x, min_y, max_y, min_z, max_z). I just want to measure the values (4 lines) as i mentioned in picture. I don't know exactly how to calculate those 4 values.

jeske's picture

darkprince - in order to measure the lengths, you need not only the float min_x, but the Vector3 at which that min_x occurred. That is what winterhell's code computes. If you save the entire Vector3 instead of just the float value, then you can just measure them.. as in..

float span_x = (min_x - max_x).Length; // length 2
float span_y = (min_y - max_y).Length; // length 4

Two of the lengths in your diagram are this type of span. The other two appear to be..

float length_1 = (max_y - new Vector3(min_x.x,max_y.y,max_y.z)).Length;
float length_3 = (min_y - new Vector3(min_x.x,min_y.y,min_y.z)).Length;

flopoloco's picture

Is this the model of an actual human foot?

These specific lines must be somehow important, unfortunately I have not a clue about this theory.
You will need to find mathematics related to medical anatomy or anthropometry.

http://www.dh.aist.go.jp/research/centered/anthropometry/fig/Fig_foot_5....
http://www.dh.aist.go.jp/research/centered/anthropometry/M_footmes_e.htm...
http://www.iwl.jp/main/mark_dimension.html

But if you want to be sure and find a proper methodology, you might invest in a medical book because it looks like this information is hard to find.

darkprinze's picture

Thanks winterhell and jeske. I got it. I confused with 3d axis placement in bounding box. is there any picture reference for understanding the axis (like min_x, max_x, min_y, max_y, min_z, max_z) within box?

@ flopoloco: Yeah. That model is an actual human foot. We have a scanner to scan the foot, and my job is to reconstruct the cloud and creating GUI for view and interact with mesh. Thats why i needed those measurements. The product is in research phase, and i may need to have a look at medical anatomy in future.

flopoloco's picture

Awesome project, good to know that you use OpenTK as well.

mak308's picture

Is this the model of an actual human foot?

darkprinze's picture

Yes. Its an actual human foot, but only with one camera. I am just playing with one camera and there are 8 cameras which will give complete foot with curves and etc. The reason you don't see the gap between fingers is because you scan your foot with custom made socks.

darkprinze's picture

I needed to draw the line to points as displayed in picture. Can i draw simply using the same measurement values with simple code?

GL.PushMatrix();
            GL.LineWidth(2.5f);
            GL.Color3(System.Drawing.Color.Red);
            GL.Begin(PrimitiveType.Lines);
            GL.Vertex3(max_y );
            GL.Vertex3(new Vector3(min_x.x,max_y.y,max_y.z));
            GL.End();
            GL.PopMatrix();

I don't think that will work. Any ideas?

Edit: not working. I think i am passing the wrong vectors.

flopoloco's picture

Hi, I have created a prototype of the application.

I hope it helps because I don't know anything else to suggest.

If something does not make sense, visit my blog where I post various code snippets.

using System;
using System.Collections.Generic;
using System.Drawing;
using OpenTK;
using OpenTK.Input;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
 
 
namespace FootLines
{
	class Foot
	{
		/// <summary>Dimensions in milimeters</summary>
		public Vector3 Position;
		public Vector3 Size;
		public Vector3 HalfSize;
		public Vector3 BoundA;
		public Vector3 BoundB;
		public List<FootMeasurement> Measurements;
 
		public void CalculateBounds()
		{
			BoundA = new Vector3();
			BoundB = new Vector3();
			HalfSize = new Vector3(Size.X / 2, Size.Y / 2, Size.Z / 2);
			BoundA = Position - HalfSize;
			BoundB = Position + HalfSize;
		}
 
		public Vector3 TransformMeasurement(Vector3 position)
		{
			var p = position + BoundA;
			// I like to flip the X coordinate just to make the values better on the eye.
			p.X *= -1f; 
			return p;
		}
	}
 
	class FootMeasurement
	{
		public Vector3 A;
		public Vector3 B;
		public Color LineColor;
	}
 
	// Original camera code posted here: http://www.opentk.com/node/3756
	class FirstPersonCamera
	{
		public Vector3 Position;
		public Vector3 Rotation;
		public Quaternion Orientation;
 
		public Matrix4 Matrix;
		public Matrix4 Model;
		public Matrix4 Projection;
 
		public FirstPersonCamera()
		{
			Matrix = Matrix4.Identity;
			Projection = Matrix4.Identity;
			Orientation = Quaternion.Identity;
		}
 
		public void Update()
		{
			Orientation =
				Quaternion.FromAxisAngle(Vector3.UnitY, Rotation.Y) *
				Quaternion.FromAxisAngle(Vector3.UnitX, Rotation.X);
 
			var forward = Vector3.Transform(Vector3.UnitZ, Orientation);
			Model = Matrix4.LookAt(Position, Position + forward, Vector3.UnitY);
			Matrix = Model * Projection;
		}
 
		public void Resize(int width, int height)
		{
			Projection = Matrix4.CreatePerspectiveFieldOfView(
				MathHelper.PiOver4, (float)width/height, 0.1f, 1000f
			);
		}
 
		public void TurnX(float a)
		{
			Rotation.X += a;
			Rotation.X = MathHelper.Clamp(Rotation.X, -1.57f, 1.57f);
		}
 
		public void TurnY(float a)
		{
			Rotation.Y += a;
			Rotation.Y = ClampCircular(Rotation.Y, 0, MathHelper.TwoPi);
		}
 
		public void MoveX(float a)
		{
			Position += Vector3.Transform(Vector3.UnitX * a, Quaternion.FromAxisAngle(Vector3.UnitY, Rotation.Y));
		}
 
		public void MoveY(float a)
		{
			Position += Vector3.Transform(Vector3.UnitY * a, Quaternion.FromAxisAngle(Vector3.UnitY, Rotation.Y));
		}
 
		public void MoveZ(float a)
		{
			Position += Vector3.Transform(Vector3.UnitZ * a, Quaternion.FromAxisAngle(Vector3.UnitY, Rotation.Y));
		}
 
		public void MoveYLocal(float a)
		{
			Position += Vector3.Transform(Vector3.UnitY * a, Orientation);
		}
 
		public void MoveZLocal(float a)
		{
			Position += Vector3.Transform(Vector3.UnitZ * a, Orientation);
		}
 
		public static float ClampCircular(float n, float min, float max)
		{
			if (n >= max) n -= max;
			if (n < min) n += max;
			return n;
		}
	}
 
	class MainClass
	{
		public static void Main(string[] args)
		{
			#region OpenTK stuff
			var window = new GameWindow();
			var mouseSpeed = new Vector2();
			var mouseSpeedValue = 0.5f;
			var camera = new FirstPersonCamera();
			// Instead of finding a way to calculate them, I grabbed them from debugger.
			camera.Position = new Vector3(-7.867702f, 368.3353f, -82.59438f);
			camera.Rotation = new Vector3(1.327627f, 0.007966042f, 0f);
			#endregion
 
			// Create a foot object
			var foot = new Foot();
			foot.Size = new Vector3(90, 50, 240); // Coordinates in mm.
			foot.Position = new Vector3(0, 25, 0); // An additional translation to lay the model on the "floor".
			foot.CalculateBounds();
 
			// Create the measurements
			var m0 = new FootMeasurement();
			var m1 = new FootMeasurement();
			var m2 = new FootMeasurement();
			var m4 = new FootMeasurement();
 
			// Set the measurement coordinates
			// these are hardcoded, not based on valid methodology
			// I added them only as means of prototyping
 
			// How to interpret the coordinates
			// just like having a Photoshop image
			// X and Y in Photoshop are equivalent to X and Z in OpenTK
			// Only one difference is that Z if increazed goes forward.
 
			// Test the diagonal of the box
			m0.A = new Vector3(0, 0, 0);
			m0.B = new Vector3(foot.Size);
			m0.LineColor = Color.Yellow;
 
			// Create the 1 - Length measurement
			m1.A = new Vector3(10, 0, 0);
			m1.B = new Vector3(0, 0, 150);
			m1.LineColor = Color.Red;
 
			// Create the 2 - Length measurement
			m2.A = new Vector3(45, 0, 0);
			m2.B = new Vector3(80, 0, 240);
			m2.LineColor = Color.DarkRed;
 
			// Create the 4 - Length measurement
			m4.A = new Vector3(m1.B);
			m4.B = new Vector3(90, 0, 180);
			m4.LineColor = Color.Green;
 
			foot.Measurements = new List<FootMeasurement>();
			foot.Measurements.Add(m0);
			foot.Measurements.Add(m1);
			foot.Measurements.Add(m2);
			foot.Measurements.Add(m4);
 
			window.Load += (object sender, EventArgs e) => 
			{
				GL.Enable(EnableCap.DepthTest);
				GL.ClearColor(System.Drawing.Color.CornflowerBlue);
			};
 
			Func<Key, Key, float, float> checkKeyState = (_keyA, _keyB, _value) =>
			{
				if (window.Keyboard[_keyA]) return  _value;
				if (window.Keyboard[_keyB]) return -_value;
				return 0f;
			};
 
			window.Resize += (object sender, EventArgs e) => { camera.Resize(window.Width, window.Height); };
 
			window.UpdateFrame += (object sender, FrameEventArgs e) => 
			{
				#region Camera input
 
				var time = (float)e.Time;
				var moveSpeed = 50*time;
 
				if (window.Keyboard[Key.ShiftLeft])
					moveSpeed = 100f * time;
 
				mouseSpeed.X = window.Mouse.YDelta * mouseSpeedValue * time;
				mouseSpeed.Y = window.Mouse.XDelta * mouseSpeedValue * time;
 
				if (window.Mouse[MouseButton.Left])
				{
					camera.TurnX( mouseSpeed.X);
					camera.TurnY(-mouseSpeed.Y);
				}
 
				camera.MoveX(checkKeyState(Key.A, Key.D, moveSpeed));
 
				if (window.Keyboard[Key.ControlLeft])
				{
					camera.MoveYLocal(checkKeyState(Key.Space, Key.C, moveSpeed));
					camera.MoveZLocal(checkKeyState(Key.W, Key.S, moveSpeed));
				}
				else
				{
					camera.MoveY(checkKeyState(Key.Space, Key.C, moveSpeed));
					camera.MoveZ(checkKeyState(Key.W, Key.S, moveSpeed));
				}
 
				#endregion
 
				camera.Update();
			};
 
			window.RenderFrame += (object sender, FrameEventArgs e) =>
			{
				GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
 
				GL.LoadMatrix(ref camera.Matrix);
				GL.LineWidth(1f);
 
				// Test the DrawBox method
//				GL.Color3(Color.Yellow);
//				DrawBox(new Vector3(-100), new Vector3(100));
//				DrawBox(Vector3.Zero, new Vector3(100));
 
				// Draw the bounds of the foot
				GL.Color3(Color.Cyan);
				DrawBox(foot.BoundA, foot.BoundB);
 
				// Draw the measurement lines
				GL.LineWidth(4f);
				GL.Begin(BeginMode.Lines);
				foreach (var i in foot.Measurements)
				{
					GL.Color3(i.LineColor);
					GL.Vertex3(foot.TransformMeasurement(i.A));
					GL.Vertex3(foot.TransformMeasurement(i.B));
				}
				GL.End();
 
				window.SwapBuffers();
			};
 
			window.Run();
		}
 
		public static void DrawBox(Vector3 pos1, Vector3 pos2)
		{
			// Bottom
			GL.Begin(PrimitiveType.LineLoop);
			GL.Vertex3(pos1.X, pos1.Y, pos1.Z);
			GL.Vertex3(pos2.X, pos1.Y, pos1.Z);
			GL.Vertex3(pos2.X, pos1.Y, pos2.Z);
			GL.Vertex3(pos1.X, pos1.Y, pos2.Z);
			GL.End();
 
			// Top
			GL.Begin(PrimitiveType.LineLoop);
			GL.Vertex3(pos1.X, pos2.Y, pos1.Z);
			GL.Vertex3(pos2.X, pos2.Y, pos1.Z);
			GL.Vertex3(pos2.X, pos2.Y, pos2.Z);
			GL.Vertex3(pos1.X, pos2.Y, pos2.Z);
			GL.End();
 
			// Vertical
			GL.Begin(PrimitiveType.Lines);
			GL.Vertex3(pos1.X, pos1.Y, pos1.Z);
			GL.Vertex3(pos1.X, pos2.Y, pos1.Z);
			GL.Vertex3(pos2.X, pos1.Y, pos1.Z);
			GL.Vertex3(pos2.X, pos2.Y, pos1.Z);
			GL.Vertex3(pos2.X, pos1.Y, pos2.Z);
			GL.Vertex3(pos2.X, pos2.Y, pos2.Z);
			GL.Vertex3(pos1.X, pos1.Y, pos2.Z);
			GL.Vertex3(pos1.X, pos2.Y, pos2.Z);
			GL.End();		
		}
	}
}