// build tree of boxes as sequential array void build_sequential(DCurve3 curve) { int NV = curve.VertexCount; int N = NV; int boxCount = 0; layers = 0; layer_counts = new List <int>(); // count how many boxes in each layer, building up from initial segments int bi = 0; while (N > 1) { int layer_boxes = (N / 2) + (N % 2 == 0 ? 0 : 1); boxCount += layer_boxes; N = layer_boxes; layer_counts.Add(layer_boxes); bi += layer_boxes; layers++; } boxes = new Box3d[boxCount]; bi = 0; // make first layer for (int si = 0; si < NV; si += 2) { Vector3d v1 = curve[(si + 1) % NV]; Segment3d seg1 = new Segment3d(curve[si], v1); Box3d box = new Box3d(seg1); if (si < NV - 1) { Segment3d seg2 = new Segment3d(v1, curve[(si + 2) % NV]); Box3d box2 = new Box3d(seg2); box = Box3d.Merge(ref box, ref box2); } boxes[bi++] = box; } // repeatedly build layers until we hit a single box N = bi; int prev_layer_start = 0; bool done = false; while (done == false) { int layer_start = bi; for (int k = 0; k < N; k += 2) { Box3d mbox = Box3d.Merge(ref boxes[prev_layer_start + k], ref boxes[prev_layer_start + k + 1]); boxes[bi++] = mbox; } N = (N / 2) + (N % 2 == 0 ? 0 : 1); prev_layer_start = layer_start; if (N == 1) { done = true; } } }
// ported from WildMagic5 Wm5ContBox3.cpp::MergeBoxes public static Box3d Merge(ref Box3d box0, ref Box3d box1) { // Construct a box that contains the input boxes. Box3d box = new Box3d(); // The first guess at the box center. This value will be updated later // after the input box vertices are projected onto axes determined by an // average of box axes. box.Center = 0.5 * (box0.Center + box1.Center); // A box's axes, when viewed as the columns of a matrix, form a rotation // matrix. The input box axes are converted to quaternions. The average // quaternion is computed, then normalized to unit length. The result is // the slerp of the two input quaternions with t-value of 1/2. The result // is converted back to a rotation matrix and its columns are selected as // the merged box axes. Quaterniond q0 = new Quaterniond(), q1 = new Quaterniond(); Matrix3d rot0 = new Matrix3d(ref box0.AxisX, ref box0.AxisY, ref box0.AxisZ, false); q0.SetFromRotationMatrix(ref rot0); Matrix3d rot1 = new Matrix3d(ref box1.AxisX, ref box1.AxisY, ref box1.AxisZ, false); q1.SetFromRotationMatrix(ref rot1); if (q0.Dot(q1) < 0) { q1 = -q1; } Quaterniond q = q0 + q1; double invLength = 1.0 / Math.Sqrt(q.Dot(q)); q = q * invLength; Matrix3d q_mat = q.ToRotationMatrix(); box.AxisX = q_mat.Column(0); box.AxisY = q_mat.Column(1); box.AxisZ = q_mat.Column(2); //q.ToRotationMatrix(box.Axis); // Project the input box vertices onto the merged-box axes. Each axis // D[i] containing the current center C has a minimum projected value // min[i] and a maximum projected value max[i]. The corresponding end // points on the axes are C+min[i]*D[i] and C+max[i]*D[i]. The point C // is not necessarily the midpoint for any of the intervals. The actual // box center will be adjusted from C to a point C' that is the midpoint // of each interval, // C' = C + sum_{i=0}^2 0.5*(min[i]+max[i])*D[i] // The box extents are // e[i] = 0.5*(max[i]-min[i]) int i, j; double dot; Vector3d[] vertex = new Vector3d[8]; Vector3d pmin = Vector3d.Zero; Vector3d pmax = Vector3d.Zero; box0.ComputeVertices(vertex); for (i = 0; i < 8; ++i) { Vector3d diff = vertex[i] - box.Center; for (j = 0; j < 3; ++j) { dot = box.Axis(j).Dot(ref diff); if (dot > pmax[j]) { pmax[j] = dot; } else if (dot < pmin[j]) { pmin[j] = dot; } } } box1.ComputeVertices(vertex); for (i = 0; i < 8; ++i) { Vector3d diff = vertex[i] - box.Center; for (j = 0; j < 3; ++j) { dot = box.Axis(j).Dot(ref diff); if (dot > pmax[j]) { pmax[j] = dot; } else if (dot < pmin[j]) { pmin[j] = dot; } } } // [min,max] is the axis-aligned box in the coordinate system of the // merged box axes. Update the current box center to be the center of // the new box. Compute the extents based on the new center. for (j = 0; j < 3; ++j) { box.Center += (0.5 * (pmax[j] + pmin[j])) * box.Axis(j); box.Extent[j] = 0.5 * (pmax[j] - pmin[j]); } return(box); }
// solidBox == false means fully contained segment does not intersect public IntrSegment3Box3(Segment3d s, Box3d b, bool solidBox) { segment = s; box = b; this.solid = solidBox; }
/// <summary> /// test if ray intersects box. /// expandExtents allows you to scale box for hit-testing purposes. /// </summary> public static bool Intersects(ref Ray3d ray, ref Box3d box, double expandExtents = 0) { Vector3d WdU = Vector3d.Zero; Vector3d AWdU = Vector3d.Zero; Vector3d DdU = Vector3d.Zero; Vector3d ADdU = Vector3d.Zero; Vector3d AWxDdU = Vector3d.Zero; double RHS; Vector3d diff = ray.Origin - box.Center; Vector3d extent = box.Extent + expandExtents; WdU[0] = ray.Direction.Dot(ref box.AxisX); AWdU[0] = Math.Abs(WdU[0]); DdU[0] = diff.Dot(ref box.AxisX); ADdU[0] = Math.Abs(DdU[0]); if (ADdU[0] > extent.x && DdU[0] * WdU[0] >= (double)0) { return(false); } WdU[1] = ray.Direction.Dot(ref box.AxisY); AWdU[1] = Math.Abs(WdU[1]); DdU[1] = diff.Dot(ref box.AxisY); ADdU[1] = Math.Abs(DdU[1]); if (ADdU[1] > extent.y && DdU[1] * WdU[1] >= (double)0) { return(false); } WdU[2] = ray.Direction.Dot(ref box.AxisZ); AWdU[2] = Math.Abs(WdU[2]); DdU[2] = diff.Dot(ref box.AxisZ); ADdU[2] = Math.Abs(DdU[2]); if (ADdU[2] > extent.z && DdU[2] * WdU[2] >= (double)0) { return(false); } Vector3d WxD = ray.Direction.Cross(diff); AWxDdU[0] = Math.Abs(WxD.Dot(ref box.AxisX)); RHS = extent.y * AWdU[2] + extent.z * AWdU[1]; if (AWxDdU[0] > RHS) { return(false); } AWxDdU[1] = Math.Abs(WxD.Dot(ref box.AxisY)); RHS = extent.x * AWdU[2] + extent.z * AWdU[0]; if (AWxDdU[1] > RHS) { return(false); } AWxDdU[2] = Math.Abs(WxD.Dot(ref box.AxisZ)); RHS = extent.x * AWdU[1] + extent.y * AWdU[0]; if (AWxDdU[2] > RHS) { return(false); } return(true); }
public IntrRay3Box3(Ray3d r, Box3d b) { ray = r; box = b; }
public IntrLine3Box3(Line3d l, Box3d b) { line = l; box = b; }
// build tree of boxes as sequential array void build_sequential(DCurve3 curve) { int NV = curve.VertexCount; int N = (curve.Closed) ? NV : NV - 1; int boxCount = 0; layers = 0; layer_counts = new List <int>(); // count how many boxes in each layer, building up from initial segments int bi = 0; while (N > 1) { int layer_boxes = (N / 2) + (N % 2 == 0 ? 0 : 1); boxCount += layer_boxes; N = layer_boxes; layer_counts.Add(layer_boxes); bi += layer_boxes; layers++; } // [RMS] this case happens if N = 1, previous loop is skipped and we have to // hardcode initialization to this redundant box if (layers == 0) { layers = 1; boxCount = 1; layer_counts = new List <int>() { 1 }; } boxes = new Box3d[boxCount]; bi = 0; // make first layer int NStop = (curve.Closed) ? NV : NV - 1; for (int si = 0; si < NStop; si += 2) { Vector3d v1 = curve[(si + 1) % NV]; Segment3d seg1 = new Segment3d(curve[si], v1); Box3d box = new Box3d(seg1); if (si < NV - 1) { Segment3d seg2 = new Segment3d(v1, curve[(si + 2) % NV]); Box3d box2 = new Box3d(seg2); box = Box3d.Merge(ref box, ref box2); } boxes[bi++] = box; } // repeatedly build layers until we hit a single box N = bi; if (N == 1) { return; } int prev_layer_start = 0; bool done = false; while (done == false) { int layer_start = bi; for (int k = 0; k < N; k += 2) { Box3d mbox = Box3d.Merge(ref boxes[prev_layer_start + k], ref boxes[prev_layer_start + k + 1]); boxes[bi++] = mbox; } N = (N / 2) + (N % 2 == 0 ? 0 : 1); prev_layer_start = layer_start; if (N == 1) { done = true; } } }