예제 #1
0
        // 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;
                }
            }
        }
예제 #2
0
        // 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);
        }
예제 #3
0
 // solidBox == false means fully contained segment does not intersect
 public IntrSegment3Box3(Segment3d s, Box3d b, bool solidBox)
 {
     segment = s; box = b; this.solid = solidBox;
 }
예제 #4
0
        /// <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);
        }
예제 #5
0
 public IntrRay3Box3(Ray3d r, Box3d b)
 {
     ray = r; box = b;
 }
예제 #6
0
 public IntrLine3Box3(Line3d l, Box3d b)
 {
     line = l; box = b;
 }
예제 #7
0
        // 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;
                }
            }
        }