예제 #1
0
파일: geom.cs 프로젝트: thild/sawdust
 public static bool intersect(BoundingBox3d bb1, BoundingBox3d bb2)
 {
     if (fp.lt_inches(bb1.xmax, bb2.xmin))
     {
         return(false);
     }
     if (fp.lt_inches(bb2.xmax, bb1.xmin))
     {
         return(false);
     }
     if (fp.lt_inches(bb1.ymax, bb2.ymin))
     {
         return(false);
     }
     if (fp.lt_inches(bb2.ymax, bb1.ymin))
     {
         return(false);
     }
     if (fp.lt_inches(bb1.zmax, bb2.zmin))
     {
         return(false);
     }
     if (fp.lt_inches(bb2.zmax, bb1.zmin))
     {
         return(false);
     }
     return(true);
 }
예제 #2
0
        public void test_bb3d()
        {
            BoundingBox3d bb = BoundingBox3d.FromArrayOfPoints(ut.MakePoly(new xyz(0, 0, 0), new xyz(5, 5, 5)));

            Assert.IsTrue(bb.PointInside(new xyz(3, 3, 3)));
            Assert.IsTrue(bb.PointInside(new xyz(0, 0, 0)));
            Assert.IsTrue(bb.PointInside(new xyz(5, 5, 5)));
            Assert.IsTrue(bb.PointInside(new xyz(5, 0, 5)));
            Assert.IsTrue(bb.PointInside(new xyz(0, 0, 5)));
            Assert.IsTrue(bb.PointInside(new xyz(0, 4, 0)));
            Assert.IsFalse(bb.PointInside(new xyz(0, 6, 0)));
            Assert.IsFalse(bb.PointInside(new xyz(0, 0, -1)));
            Assert.IsFalse(bb.PointInside(new xyz(7, 6, 0)));
            Assert.IsFalse(bb.PointInside(new xyz(7, 7, 7)));

            BoundingBox3d bb2 = BoundingBox3d.FromArrayOfPoints(ut.MakePoly(new xyz(8, 8, 8), new xyz(9, 9, 9)));

            bb = bb + bb2;
            Assert.IsTrue(bb.PointInside(new xyz(3, 3, 3)));
            Assert.IsTrue(bb.PointInside(new xyz(0, 0, 0)));
            Assert.IsTrue(bb.PointInside(new xyz(5, 5, 5)));
            Assert.IsTrue(bb.PointInside(new xyz(5, 0, 5)));
            Assert.IsTrue(bb.PointInside(new xyz(0, 0, 5)));
            Assert.IsTrue(bb.PointInside(new xyz(0, 4, 0)));

            Assert.IsTrue(bb.PointInside(new xyz(8, 8, 8)));
            Assert.IsTrue(bb.PointInside(new xyz(7, 7, 7)));
        }
예제 #3
0
파일: bool3d.cs 프로젝트: thild/sawdust
        public static CompoundSolid Subtract(CompoundSolid s1, Solid s2)
        {
            CompoundSolid result = new CompoundSolid();

            BoundingBox3d bb2 = s2.GetBoundingBox();

            bool bCheck = result.HasSubOverlaps;

            foreach (Solid s in s1.Subs)
            {
                BoundingBox3d bb1 = s.GetBoundingBox();
                if (!BoundingBox3d.intersect(bb1, bb2))
                {
                    result.AddSub(s.Clone(), bCheck);
                }
                else
                {
                    result.AddSub(Subtract(s, s2), bCheck);
                }
            }

#if DEBUG
            result.AssertNoNameClashes();
#endif

            return(result);
        }
예제 #4
0
        public static bool MightIntersect_BB(List <xyz> main1, List <xyz> main2)
        {
            BoundingBox3d bb1 = BoundingBox3d.FromArrayOfPoints(main1);
            BoundingBox3d bb2 = BoundingBox3d.FromArrayOfPoints(main2);

            return(BoundingBox3d.intersect(bb1, bb2));
        }
예제 #5
0
파일: wood.cs 프로젝트: thild/sawdust
        public static CompoundSolid Crosscut_Or_Rip(CompoundSolid sol, HalfEdge he, Inches distAlongEdge, double miter, double tilt)
        {
            Face f = he.face;

            // TODO fix these names
            string[] fnames = new string[] {
                "miter_top",
                "miter_right",
                "miter_left",
                "miter_bottom",
                "miter",                                // the primary face name which gets left
                "miter_below",
            };

            xyz nrml   = f.UnitNormal();
            xyz origin = he.to + he.GetInwardNormal() * distAlongEdge;

            // vx is in the direction of the cut
            xyz vx = ut.RotateUnitVector(-he.UnitVector(), -miter, nrml);

            // now rotate nrml for tilt
            nrml = ut.RotateUnitVector(nrml, tilt, vx);

            // origin is going to be the corner of the cutter box.
            // right now it is sitting on the face.  we need to
            // move it further away.  calculate intersections with
            // the boundingbox of the compoundsolid as a whole.

            BoundingBox3d bb     = sol.GetBoundingBox();
            double        d_vx   = bb.IntersectRay_Planes_Max(origin, -vx);
            double        d_nrml = bb.IntersectRay_Planes_Max(origin, nrml);

            // TODO this approach creates a bb which is too big.  do we care?

            // now move origin far enough back behind the face
            origin.subtract_in_place((d_vx + 2) * vx);
            // and up above the face
            origin = origin + (d_nrml + 2) * nrml;

            xyz vy = xyz.cross(nrml, vx).normalize_in_place();
            xyz vz = -nrml;

            d_vx = bb.IntersectRay_Planes_Max(origin, vx);
            double d_vy = bb.IntersectRay_Planes_Max(origin, vy);
            double d_vz = bb.IntersectRay_Planes_Max(origin, vz);

            // now calculate proper sizes for the cutter
            double dx = d_vx + 2;
            double dy = d_vy + 2;
            double dz = d_vz + 2;

            Solid cutter = CreateCutter_Box(string.Format("{0}_{1}", f.name, he.Opposite().face.name), origin, vx, nrml, new xyz(dx, dy, dz), fnames);

            //sol = sol.Clone();
            //sol.AddSub(cutter);
            //return sol;
            return(bool3d.Subtract(sol, cutter));
        }
예제 #6
0
파일: geom.cs 프로젝트: thild/sawdust
 public void Add(BoundingBox3d b)
 {
     xmin = Math.Min(xmin, b.xmin);
     ymin = Math.Min(ymin, b.ymin);
     zmin = Math.Min(zmin, b.zmin);
     xmax = Math.Max(xmax, b.xmax);
     ymax = Math.Max(ymax, b.ymax);
     zmax = Math.Max(zmax, b.zmax);
 }
예제 #7
0
파일: geom.cs 프로젝트: thild/sawdust
        public static BoundingBox3d CalcIntersection(BoundingBox3d a, BoundingBox3d b)
        {
            BoundingBox3d r = new BoundingBox3d();

            r.xmin = Math.Max(a.xmin, b.xmin);
            r.ymin = Math.Max(a.ymin, b.ymin);
            r.zmin = Math.Max(a.zmin, b.zmin);
            r.xmax = Math.Min(a.xmax, b.xmax);
            r.ymax = Math.Min(a.ymax, b.ymax);
            r.zmax = Math.Min(a.zmax, b.zmax);

            return(r);
        }
예제 #8
0
파일: geom.cs 프로젝트: thild/sawdust
        public static BoundingBox3d operator +(BoundingBox3d a, BoundingBox3d b)
        {
            BoundingBox3d r = new BoundingBox3d();

            r.xmin = Math.Min(a.xmin, b.xmin);
            r.ymin = Math.Min(a.ymin, b.ymin);
            r.zmin = Math.Min(a.zmin, b.zmin);
            r.xmax = Math.Max(a.xmax, b.xmax);
            r.ymax = Math.Max(a.ymax, b.ymax);
            r.zmax = Math.Max(a.zmax, b.zmax);

            return(r);
        }
예제 #9
0
파일: geom.cs 프로젝트: thild/sawdust
        // TODO this is only used in the unit tests
        internal static BoundingBox3d FromPoints(params xyz[] a)
        {
            BoundingBox3d bb = new BoundingBox3d();

            foreach (xyz v in a)
            {
                bb.xmin = Math.Min(bb.xmin, v.x);
                bb.ymin = Math.Min(bb.ymin, v.y);
                bb.zmin = Math.Min(bb.zmin, v.z);
                bb.xmax = Math.Max(bb.xmax, v.x);
                bb.ymax = Math.Max(bb.ymax, v.y);
                bb.zmax = Math.Max(bb.zmax, v.z);
            }
            return(bb);
        }
예제 #10
0
파일: geom.cs 프로젝트: thild/sawdust
        internal static BoundingBox3d FromArrayOfPoints(List <xyz> a)
        {
            BoundingBox3d bb = new BoundingBox3d();

            a.ForEach(delegate(xyz v)
            {
                bb.xmin = Math.Min(bb.xmin, v.x);
                bb.ymin = Math.Min(bb.ymin, v.y);
                bb.zmin = Math.Min(bb.zmin, v.z);
                bb.xmax = Math.Max(bb.xmax, v.x);
                bb.ymax = Math.Max(bb.ymax, v.y);
                bb.zmax = Math.Max(bb.zmax, v.z);
            }
                      );
            return(bb);
        }
예제 #11
0
파일: bool3d.cs 프로젝트: thild/sawdust
        public static void PartitionFace_SplitEdges(List <seg3d> segs, Solid s2, BoundingBox3d bb2, bool reverse)
        {
            List <seg3d> rm   = new List <seg3d>();
            List <seg3d> news = new List <seg3d>();

            for (int i = 0; i < segs.Count; i++)
            {
                seg3d s = segs[i];
                if (bb2.SegmentCannotIntersect(s.a, s.b))
                {
                    continue;
                }

                for (int j = 0; j < s2.Faces.Count; j++)
                {
                    Face f2 = s2.Faces[j];

                    xyz hit = f2.CalcSegmentFaceIntersection_HitOnly(s);
                    if (hit != null)
                    {
                        rm.Add(s);

                        seg3d to_the_face        = new seg3d(s.a, hit, s.origin);
                        seg3d away_from_the_face = new seg3d(hit, s.b, s.origin);

                        news.Add(to_the_face);
                        news.Add(away_from_the_face);

                        break;
                    }
                }
            }

            if (news.Count > 0)
            {
                PartitionFace_SplitEdges(news, s2, bb2, reverse);

                foreach (seg3d s in rm)
                {
                    segs.Remove(s);
                }
                foreach (seg3d s in news)
                {
                    segs.Add(s);
                }
            }
        }
예제 #12
0
파일: bool3d.cs 프로젝트: thild/sawdust
        public static Solid Subtract(Solid s1, Solid s2)
        {
            bsp3d bsp1 = new bsp3d(s1);
            bsp3d bsp2 = new bsp3d(s2);

            BoundingBox3d bb1 = s1.GetBoundingBox();
            BoundingBox3d bb2 = s2.GetBoundingBox();

            Solid s3 = new Solid(s1.name, s1.material);

            if (s1.board_origin != null)
            {
                s3.board_origin = s1.board_origin.copy();
                s3.board_u      = s1.board_u.copy();
                s3.board_v      = s1.board_v.copy();
                s3.board_w      = s1.board_w.copy();
            }

            List <segpile> piles = new List <segpile>();

            for (int ndx_f1 = 0; ndx_f1 < s1.Faces.Count; ndx_f1++)
            {
                Face f1 = s1.Faces[ndx_f1];
                piles.Add(PartitionFace(s3, f1, s2, bb1, bb2, bsp1, bsp2, false));
            }

            for (int ndx_f2 = 0; ndx_f2 < s2.Faces.Count; ndx_f2++)
            {
                Face f2 = s2.Faces[ndx_f2];
                piles.Add(PartitionFace(s3, f2, s1, bb1, bb2, bsp2, bsp1, true));
            }

            foreach (segpile sp in piles)
            {
                if (sp.segs.Count > 0)
                {
                    s3.CreateFacesFromPileOfSegments(sp.name, sp.OriginalName, sp.Shade, sp.segs, sp.reverse);
                }
            }

            s3.FixCollinearTrios();

            return(s3);
        }
예제 #13
0
        public void test_cube()
        {
            Solid         s1  = Builtin_Solids.CreateCube("s1", 5);
            bsp3d         bsp = new bsp3d(s1);
            BoundingBox3d bb  = BoundingBox3d.FromArrayOfPoints(s1.Vertices);

            foreach (xyz v in s1.Vertices)
            {
                Assert.AreEqual(PointInPoly.Coincident, bsp.PointInPolyhedron(v));
                Assert.IsTrue(bb.PointInside(v));
            }
            foreach (Face f in s1.Faces)
            {
                xyz v = f.GetCenter();
                xyz n = f.UnitNormal();
                Assert.AreEqual(PointInPoly.Coincident, bsp.PointInPolyhedron(v));
                Assert.AreEqual(PointInPoly.Outside, bsp.PointInPolyhedron(v + n));
                Assert.AreEqual(PointInPoly.Inside, bsp.PointInPolyhedron(v - n));
                Assert.IsTrue(bb.PointInside(v));
                Assert.IsFalse(bb.PointInside(v + n));
                Assert.IsTrue(bb.PointInside(v - n));
            }
            foreach (Face f in s1.Faces)
            {
                foreach (HalfEdge h in f.MainLoop)
                {
                    xyz v = h.Center();
                    xyz n = h.GetInwardNormal();
                    Assert.IsTrue(bb.PointInside(v));
                    Assert.IsTrue(bb.PointInside(v + n));
                    Assert.IsFalse(bb.PointInside(v - n));
                    Assert.AreEqual(PointInPoly.Coincident, bsp.PointInPolyhedron(v));
                    Assert.AreEqual(PointInPoly.Coincident, bsp.PointInPolyhedron(v + n));
                    Assert.AreEqual(PointInPoly.Outside, bsp.PointInPolyhedron(v - n));
                }
            }
            Assert.AreEqual(PointInPoly.Inside, bsp.PointInPolyhedron(s1.GetCenter()));
            Assert.IsTrue(bb.PointInside(s1.GetCenter()));
        }
예제 #14
0
파일: bool3d.cs 프로젝트: thild/sawdust
        public static segpile PartitionFace(Solid s3, Face f1, Solid s2, BoundingBox3d bb1, BoundingBox3d bb2, bsp3d bsp1, bsp3d bsp2, bool reverse)
        {
#if BOOL_DEBUG
            Console.Out.WriteLine("PartitionFace: f1.name={0} s2={1} reverse={2}", f1.name, s2.name, reverse);
#endif

            List <seg3d> segs = f1.CollectAllSegments();
#if BOOL_DEBUG
            ut.DumpSegments3d("CollectAllSegments", segs);
#endif

            PartitionFace_CalcFaceIntersections(segs, f1, s2, reverse);
#if BOOL_DEBUG
            ut.DumpSegments3d("CalcFaceIntersections", segs);
#endif

            PartitionFace_HandleOverlaps(segs, f1, s2, reverse);
#if BOOL_DEBUG
            ut.DumpSegments3d("HandleOverlaps", segs);
#endif

            PartitionFace_SplitEdges(segs, s2, bb2, reverse);
#if BOOL_DEBUG
            ut.DumpSegments3d("SplitEdges", segs);
#endif

#if true
            // TODO:  If we remove this call, only one unit test fails.
            // that means we usually don't need it.  I'd love to find a
            // way to decide when we need it so we can save the call
            // most of the time.  The failing unit test is the two
            // mortises overlapping, a case which should never happen
            // in practice, AFAIK.

            if (!reverse) // TODO for now, only call this on the !reverse pass
            {
                PartitionFace_SplitEdges(segs, f1.solid, bb1, !reverse);
            }
#if BOOL_DEBUG
            ut.DumpSegments3d("SplitEdges2", segs);
#endif
#endif

            PartitionFace_RemoveObvious(segs, f1, s2, bsp2, reverse);
#if BOOL_DEBUG
            ut.DumpSegments3d("RemoveObvious", segs);
#endif

            PartitionFace_HandleCoplanarStuff(segs, f1, s2, reverse);
#if BOOL_DEBUG
            ut.DumpSegments3d("HandleCoplanarStuff", segs);
#endif

            PartitionFace_RemoveByDirection(segs, f1, s2, reverse);
#if BOOL_DEBUG
            ut.DumpSegments3d("RemoveByDirection", segs);
#endif

            PartitionFace_Edges_StuffInOtherSolid(segs, s2, bsp2, reverse);
#if BOOL_DEBUG
            ut.DumpSegments3d("StuffInOtherSolid", segs);
#endif

            PartitionFace_HandleEdges(segs, f1, s2, bsp2, reverse);
#if BOOL_DEBUG
            ut.DumpSegments3d("HandleEdges", segs);
#endif

            Debug.Assert((segs.Count == 0) || (segs.Count >= 3));

            string name;
            if (reverse)
            {
                name = string.Format("{0}_{1}", f1.solid.name, f1.name);
            }
            else
            {
                name = f1.name;
            }

            return(new segpile(segs, name, f1.OriginalName, f1.Shade, reverse));
        }
예제 #15
0
파일: bool3d.cs 프로젝트: thild/sawdust
        public static bool CheckIfTwoSolidsShareAnySpace(Solid s1, Solid s2)
        {
            BoundingBox3d bb1 = s1.GetBoundingBox();
            BoundingBox3d bb2 = s2.GetBoundingBox();

            if (!BoundingBox3d.intersect(bb1, bb2))
            {
                return(false);
            }

            BoundingBox3d bb3 = BoundingBox3d.CalcIntersection(bb1, bb2);

            if (fp.eq_tol(bb3.volume, 0, 0.0001))
            {
                return(false);
            }

            bsp3d bsp1 = new bsp3d(s1);
            bsp3d bsp2 = new bsp3d(s2);

            xyz c1 = s1.GetCenter();

            if (
                (bsp1.PointInPolyhedron(c1) == PointInPoly.Inside) &&
                (bsp2.PointInPolyhedron(c1) == PointInPoly.Inside)
                )
            {
                return(true);
            }
            xyz c2 = s2.GetCenter();

            if (
                (bsp2.PointInPolyhedron(c2) == PointInPoly.Inside) &&
                (bsp1.PointInPolyhedron(c2) == PointInPoly.Inside)
                )
            {
                return(true);
            }

            foreach (Face f1 in s1.Faces)
            {
                xyz p = f1.GetCenter() - f1.UnitNormal() * 0.01;
                if (
                    (bsp2.PointInPolyhedron(p) == PointInPoly.Inside) &&
                    (bsp1.PointInPolyhedron(p) == PointInPoly.Inside)
                    )
                {
                    return(true);
                }
            }

            foreach (Face f2 in s2.Faces)
            {
                xyz p = f2.GetCenter() - f2.UnitNormal() * 0.01;
                if (
                    (bsp1.PointInPolyhedron(p) == PointInPoly.Inside) &&
                    (bsp2.PointInPolyhedron(p) == PointInPoly.Inside)
                    )
                {
                    return(true);
                }
            }

            if (s1.AnyEdgePiercesAnyFace(s2))
            {
                return(true);
            }

            if (s2.AnyEdgePiercesAnyFace(s1))
            {
                return(true);
            }

            // TODO we apparently need another testhere

            return(false);
        }