Exemple #1
0
        public static CompoundSolid Drill(CompoundSolid sol, HalfEdge he, Inches x, Inches y, int count, Inches dx, Inches dy, double diameter, double depth, string id)
        {
            Face f = he.face;

            Solid cutter = new Solid(id, BoardMaterial.Find(BoardMaterial.NONE));

            for (int i = 0; i < count; i++)
            {
                CreateCutter_Drill(cutter, he, new xy(x, y), diameter, depth, (i + 1).ToString());
                x += dx;
                y += dy;
            }

            cutter.RecalcFacePlanes();

            CompoundSolid cs = bool3d.Subtract(sol, cutter);

            // find all the edges between slices we just drilled and mark those edges for no lines.
            // TODO this is probably not a very efficient way to do this, but it works
            foreach (Solid s in cs.Subs)
            {
#if not
                foreach (Edge e in s.Edges)
                {
                    string sf1 = e.a2b.face.name;
                    string sf2 = e.b2a.face.name;
                    if (sf1.StartsWith(id) && sf2.StartsWith(id) && (-1 != sf1.IndexOf("_slice_")) && (-1 != sf2.IndexOf("_slice_")))
                    {
                        e.NoLine = true;
                    }
                }
#endif

                foreach (Face fc in s.Faces)
                {
                    if (fc.name.StartsWith(id) && (-1 != fc.name.IndexOf("_slice")))
                    {
                        fc.Shade = true;
                    }
                }
            }

            return(cs);
        }
Exemple #2
0
        public static CompoundSolid Dado(CompoundSolid sol, HalfEdge heParallel, Inches distFromParallelEdge, Inches width, Inches depth, string id)
        {
            Face f = heParallel.face;

            string[] fnames = new string[] {
                "top",
                "right",
                "left",
                "bottom",
                "side_above",
                "side_below"
            };

            // TODO should we move left or right further?  what if the dado needs to be longer than this edge?  or shorter?

            Solid cutter = CreateCutter_Box(id, heParallel, new xy(0, distFromParallelEdge), new xyz(heParallel.Length(), width, depth), fnames);

            return(bool3d.Subtract(sol, cutter));
        }
Exemple #3
0
        public static CompoundSolid Mortise(CompoundSolid sol, HalfEdge he, xy pos, xyz size, int count, Inches dx, Inches dy, string id)
        {
            Solid cutter;

            if (count == 1)
            {
                string[] fnames = new string[] {
                    "NA",
                    "right",
                    "left",
                    "bottom",
                    "front",
                    "back",
                };
                cutter = CreateCutter_Box(id, he, pos, size, fnames);
            }
            else
            {
                cutter = new Solid(id, BoardMaterial.Find(BoardMaterial.NONE));

                Inches x = pos.x;
                Inches y = pos.y;
                for (int i = 0; i < count; i++)
                {
                    string[] fnames = new string[] {
                        string.Format("NA_{0}", i + 1),
                        string.Format("right_{0}", i + 1),
                        string.Format("left_{0}", i + 1),
                        string.Format("bottom_{0}", i + 1),
                        string.Format("front_{0}", i + 1),
                        string.Format("back_{0}", i + 1),
                    };
                    CreateCutter_Box(cutter, he, new xy(x, y), size, fnames);
                    x += dx;
                    y += dy;
                }

                cutter.RecalcFacePlanes();
            }

            return(bool3d.Subtract(sol, cutter));
        }
Exemple #4
0
        internal void Execute()
        {
            Errors.Clear();
            Warnings.Clear();
            annotations_PP.Clear();
            facesToBeLabeled.Clear();
            prose = null;

            try
            {
                /*
                 * This switch statement must have one case for
                 * every kind of step action.
                 *
                 * Each case in this switch statement needs to:
                 *
                 * 1.  retrieve the parameters for the step
                 * 2.  do error checking on those parameters
                 * 3.  calculate the prose description of the step
                 * 4.  execute the step
                 * 5.  add faces to be labeled
                 * 6.  add annotations
                 * */

                switch (action)
                {
                case Action.INTRO:
                {
                    prose   = "";
                    _result = plan.LastStep.Result;
                    break;
                }

                case Action.DRILL:
                {
                    Inches x     = Get_Eval("x");
                    Inches y     = Get_Eval("y");
                    Inches diam  = Get_Eval("diam");
                    Inches depth = Get_Eval("depth");
                    string id    = Get_String("id");
                    Inches dx    = Get_Eval("dx");
                    Inches dy    = Get_Eval("dy");
                    int    count = Get_Eval_Integer("count");

                    CompoundSolid cs;
                    Solid         sol;
                    Face          f;
                    HalfEdge      he;
                    Lookup(Get_String("path"), out cs, out sol, out f, out he);

                    if (depth > Limits.MAX_DRILL_DEPTH)
                    {
                        Warnings.Add(string.Format("Drill depth is absurd"));
                    }

                    StringBuilder sb = new StringBuilder();
                    if (count > 1)
                    {
                        sb.AppendFormat("Drill {2} holes\r\n{0} in diameter and {1} deep\r\n", diam.GetProse(), depth.GetProse(), count);
                        sb.AppendFormat("in the '{0}' face of the board named '{1}'\r\n", f.name, sol.name);
                        sb.AppendFormat("\r\nstarting at {0}, {1} inches from\r\nthe edge between faces '{2}' and '{3}'.\r\n", x.GetStringWithoutUnits(), y.GetStringWithoutUnits(), f.name, he.Opposite().face.name);
                        // TODO what if dx and dy are both non-zero?
                        if (dx > 0)
                        {
                            sb.AppendFormat("{0} apart", dx.GetProse());
                        }
                        else
                        {
                            sb.AppendFormat("{0} apart", dy.GetProse());
                        }
                    }
                    else
                    {
                        sb.AppendFormat("Drill a hole\r\n{0} in diameter and {1} deep\r\n", diam.GetProse(), depth.GetProse());
                        sb.AppendFormat("in the '{0}' face of the board named '{1}'\r\n", f.name, sol.name);
                        sb.AppendFormat("\r\nat {0}, {1} inches from\r\nthe edge between faces '{2}' and '{3}'.\r\n", x.GetStringWithoutUnits(), y.GetStringWithoutUnits(), f.name, he.Opposite().face.name);
                    }
                    prose = sb.ToString();

                    _result = wood.Drill(cs, he, x, y, count, dx, dy, diam, depth, id);

                    facesToBeLabeled.Add(_result.FindFace(sol.name, f.name));

                    break;
                }

                case Action.TENON:
                {
                    Inches x     = Get_Eval("x");
                    Inches y     = Get_Eval("y");
                    Inches xsize = Get_Eval("xsize");
                    Inches ysize = Get_Eval("ysize");
                    Inches depth = Get_Eval("depth");
                    string id    = Get_String("id");

                    CompoundSolid cs;
                    Solid         sol;
                    Face          f;
                    HalfEdge      he;
                    Lookup(Get_String("path"), out cs, out sol, out f, out he);

                    StringBuilder sb = new StringBuilder();
                    sb.AppendFormat("Cut a tenon\r\n{0} by {1}\r\n{2} deep\r\n", xsize.GetProse(), ysize.GetProse(), depth.GetProse());
                    sb.AppendFormat("in the '{0}' face of the board named '{1}'\r\n", f.name, sol.name);
                    sb.AppendFormat("at {0}, {1} inches from\r\nthe edge between faces '{2}' and '{3}'.\r\n", x.GetStringWithoutUnits(), y.GetStringWithoutUnits(), f.name, he.Opposite().face.name);
                    sb.AppendFormat("Call this tenon '{0}'.", id);
                    prose = sb.ToString();

                    _result = wood.Tenon(cs, he, new xy(x, y), new xyz(xsize, ysize, depth), id);

                    string _s, _f, _e;
                    ut.ParsePath(Get_String("path"), out _s, out _f, out _e);

                    Face newendface = _result.FindFace(_s, _f);
                    if (newendface != null)
                    {
                        facesToBeLabeled.Add(newendface);

                        HalfEdge heother = newendface.FindEdge(_e);
                        if (heother != null)
                        {
                            facesToBeLabeled.Add(heother.Opposite().face);
                        }

                        HalfEdge hea = newendface.FindEdge(string.Format("{0}_left", id));
                        if (hea == null)
                        {
                            hea = newendface.FindEdge(string.Format("{0}_right", id));
                        }
                        if (hea != null)
                        {
                            this.annotations_PP.Add(new Annotation_PointToPoint(hea.from, hea.to, newendface.UnitNormal(), 2));
                        }

                        hea = newendface.FindEdge(string.Format("{0}_front", id));
                        if (hea == null)
                        {
                            hea = newendface.FindEdge(string.Format("{0}_back", id));
                        }
                        if (hea != null)
                        {
                            this.annotations_PP.Add(new Annotation_PointToPoint(hea.from, hea.to, newendface.UnitNormal(), 2));
                        }
                    }

                    // TODO more annotations here for the dimensions of the shoulders?

                    break;
                }

                case Action.MORTISE:
                {
                    Inches x     = Get_Eval("x");
                    Inches y     = Get_Eval("y");
                    Inches xsize = Get_Eval("xsize");
                    Inches ysize = Get_Eval("ysize");
                    Inches depth = Get_Eval("depth");
                    string id    = Get_String("id");
                    Inches dx    = Get_Eval("dx");
                    Inches dy    = Get_Eval("dy");
                    int    count = Get_Eval_Integer("count");

                    CompoundSolid cs;
                    Solid         sol;
                    Face          f;
                    HalfEdge      he;
                    Lookup(Get_String("path"), out cs, out sol, out f, out he);

                    if (depth > Limits.MAX_MORTISE_DEPTH)
                    {
                        Warnings.Add(string.Format("Mortise depth is absurd"));
                    }

                    StringBuilder sb = new StringBuilder();
                    if (count == 1)
                    {
                        sb.AppendFormat("Cut a mortise\r\n{0} by {1}\r\n{2} deep\r\n", xsize.GetProse(), ysize.GetProse(), depth.GetProse());
                        sb.AppendFormat("in the '{0}' face of the board named '{1}'\r\n", f.name, sol.name);
                        sb.AppendFormat("at {0}, {1} inches from\r\nthe edge between faces '{2}' and '{3}'.\r\n", x.GetStringWithoutUnits(), y.GetStringWithoutUnits(), f.name, he.Opposite().face.name);
                        //sb.AppendFormat("Call this mortise '{0}'.", id);
                    }
                    else
                    {
                        sb.AppendFormat("Cut {3} mortises\r\n{0} by {1}\r\n{2} deep\r\n", xsize.GetProse(), ysize.GetProse(), depth.GetProse(), count);
                        sb.AppendFormat("in the '{0}' face of the board named '{1}'\r\n", f.name, sol.name);
                        sb.AppendFormat("starting at {0}, {1} inches from\r\nthe edge between faces '{2}' and '{3}'\r\n", x.GetStringWithoutUnits(), y.GetStringWithoutUnits(), f.name, he.Opposite().face.name);
                        // TODO what if dx and dy are both non-zero?
                        if (dx > 0)
                        {
                            sb.AppendFormat("{0} apart", dx.GetProse());
                        }
                        else
                        {
                            sb.AppendFormat("{0} apart", dy.GetProse());
                        }
                        //sb.AppendFormat("Call this mortise '{0}'.", id);
                    }
                    prose   = sb.ToString();
                    _result = wood.Mortise(cs, he, new xy(x, y), new xyz(xsize, ysize, depth), count, dx, dy, id);

                    string _s, _f, _e;
                    ut.ParsePath(Get_String("path"), out _s, out _f, out _e);
                    Face newf = _result.FindFace(_s, _f);
                    if (newf != null)
                    {
                        facesToBeLabeled.Add(newf);
                        HalfEdge heother = newf.FindEdge(_e);
                        if (heother != null)
                        {
                            facesToBeLabeled.Add(heother.Opposite().face);
                        }
                    }

                    if (count == 1)
                    {
                        // label the dimensions of the mortise.  first across the front or back
                        HalfEdge hea = _result.FindEdge(sol.name, string.Format("{0}_front", id), f.name);
                        if (hea == null)
                        {
                            hea = _result.FindEdge(sol.name, string.Format("{0}_back", id), f.name);
                        }
                        if (hea != null)
                        {
                            this.annotations_PP.Add(new Annotation_PointToPoint(hea.from, hea.to, f.UnitNormal(), 2));
                        }

                        // now along the left or right
                        hea = _result.FindEdge(sol.name, string.Format("{0}_left", id), f.name);
                        if (hea == null)
                        {
                            hea = _result.FindEdge(sol.name, string.Format("{0}_right", id), f.name);
                        }
                        if (hea != null)
                        {
                            this.annotations_PP.Add(new Annotation_PointToPoint(hea.from, hea.to, f.UnitNormal(), 2));
                        }

                        // now label the location of the mortise
                        if (newf != null)
                        {
                            hea = newf.FindEdge(string.Format("{0}_front", id));

                            if (hea != null)
                            {
                                xyz p1 = hea.from;
                                xyz p2 = newf.Measure(hea, p1);
                                if (p2 != null)
                                {
                                    this.annotations_PP.Add(new Annotation_PointToPoint(p1, p2, newf.UnitNormal(), 2));
                                }
                            }

                            hea = newf.FindEdge(string.Format("{0}_right", id));
                            if (hea != null)
                            {
                                xyz p1 = hea.from;
                                xyz p2 = newf.Measure(hea, p1);
                                if (p2 != null)
                                {
                                    this.annotations_PP.Add(new Annotation_PointToPoint(p1, p2, newf.UnitNormal(), 2));
                                }
                            }
                        }
                    }

                    break;
                }

                case Action.DADO:
                {
                    Inches dist  = Get_Eval("dist");
                    Inches width = Get_Eval("width");
                    Inches depth = Get_Eval("depth");
                    string path  = Get_String("path");
                    string id    = Get_String("id");

                    CompoundSolid cs;
                    Solid         sol;
                    Face          f;
                    HalfEdge      he;
                    Lookup(path, out cs, out sol, out f, out he);

                    StringBuilder sb = new StringBuilder();
                    sb.AppendFormat("Cut a dado\r\n{0} wide and {1} deep\r\n", width.GetProse(), depth.GetProse());
                    sb.AppendFormat("in the '{0}' face of the board named '{1}'\r\n", f.name, sol.name);
                    sb.AppendFormat("parallel to and {0} from the edge between faces '{1}' and '{2}'.\r\n", dist.GetProse(), f.name, he.Opposite().face.name);
                    sb.AppendFormat("Call this dado '{0}'.", id);
                    prose = sb.ToString();

                    _result = wood.Dado(cs, he, dist, width, depth, id);

                    facesToBeLabeled.Add(_result.FindFace(string.Format("{0}.{1}_1", sol.name, f.name)));
                    facesToBeLabeled.Add(_result.FindFace(string.Format("{0}.{1}_2", sol.name, f.name)));

                    break;
                }

                case Action.RIP:
                {
                    Inches dist  = Get_Eval("dist");
                    double taper = Get_Eval_Angle("taper");
                    double tilt  = Get_Eval_Angle("tilt");

                    CompoundSolid cs;
                    Solid         sol;
                    Face          f;
                    HalfEdge      he;
                    Lookup(Get_String("path"), out cs, out sol, out f, out he);

                    if (he.Opposite().face.GetQuality() == FaceQuality.EndGrain)          // TODO is this how we want this to work?
                    {
                        Warnings.Add("This is not really a rip.");
                    }

                    StringBuilder sb = new StringBuilder();
                    sb.AppendFormat("TODO");
                    prose = sb.ToString();

                    _result = wood.Crosscut_Or_Rip(cs, he, dist, taper, tilt);

                    facesToBeLabeled.Add(_result.FindFace(sol.name, f.name));
                    facesToBeLabeled.Add(_result.FindFace(sol.name, he.Opposite().face.name));

                    break;
                }

                case Action.CROSSCUT:
                {
                    Inches dist  = Get_Eval("dist");
                    double miter = Get_Eval_Angle("miter");
                    double tilt  = Get_Eval_Angle("tilt");

                    CompoundSolid cs;
                    Solid         sol;
                    Face          f;
                    HalfEdge      he;
                    Lookup(Get_String("path"), out cs, out sol, out f, out he);

                    if (he.Opposite().face.GetQuality() != FaceQuality.EndGrain)         // TODO is this how we want this to work?
                    {
                        Warnings.Add("This is not really a crosscut.");
                    }

                    StringBuilder sb = new StringBuilder();
                    sb.AppendFormat("TODO");
                    prose = sb.ToString();

                    _result = wood.Crosscut_Or_Rip(cs, he, dist, miter, tilt);

                    facesToBeLabeled.Add(_result.FindFace(sol.name, f.name));
                    facesToBeLabeled.Add(_result.FindFace(sol.name, he.Opposite().face.name));

                    break;
                }

                case Action.CHAMFER:
                {
                    Inches inset = Get_Eval("inset");
                    string id    = Get_String("id");

                    CompoundSolid cs;
                    Solid         sol;
                    Face          f;
                    HalfEdge      he;
                    Lookup(Get_String("path"), out cs, out sol, out f, out he);

                    StringBuilder sb = new StringBuilder();
                    sb.AppendFormat("Chamfer\r\nthe edge between the faces '{0}' and '{1}'\r\non the board '{2}'\r\n", f.name, he.Opposite().face.name, sol.name);
                    sb.AppendFormat("at a depth of {0}.", inset.GetProse());
                    prose = sb.ToString();

                    _result = wood.DoChamfer(cs, he, inset, id);

                    facesToBeLabeled.Add(_result.FindFace(sol.name, f.name));
                    facesToBeLabeled.Add(_result.FindFace(sol.name, he.Opposite().face.name));

                    xyz p1 = he.Center();

                    Face     chamface = _result.FindFace(sol.name, string.Format("{0}_2", id));
                    HalfEdge he1      = chamface.FindEdge(f.name);

                    this.annotations_PP.Add(new Annotation_PointToPoint(p1, he1.Center(), he1.Opposite().face.UnitNormal(), 2));

                    he1 = chamface.FindEdge(he.Opposite().face.name);
                    this.annotations_PP.Add(new Annotation_PointToPoint(p1, he1.Center(), he1.Opposite().face.UnitNormal(), 2));

                    break;
                }

                case Action.RABBET:
                {
                    Inches inset = Get_Eval("inset");
                    Inches depth = Get_Eval("depth");
                    string id    = Get_String("id");

                    CompoundSolid cs;
                    Solid         sol;
                    Face          f;
                    HalfEdge      he;
                    Lookup(Get_String("path"), out cs, out sol, out f, out he);

                    StringBuilder sb = new StringBuilder();
                    sb.AppendFormat("TODO");
                    prose = sb.ToString();

                    _result = wood.DoRabbet(cs, he, inset, depth, id);

                    facesToBeLabeled.Add(_result.FindFace(sol.name, f.name));
                    facesToBeLabeled.Add(_result.FindFace(sol.name, he.Opposite().face.name));

                    break;
                }

                case Action.ROUNDOVER:
                {
                    Inches radius = Get_Eval("radius");
                    string id     = Get_String("id");

                    CompoundSolid cs;
                    Solid         sol;
                    Face          f;
                    HalfEdge      he;
                    Lookup(Get_String("path"), out cs, out sol, out f, out he);

                    StringBuilder sb = new StringBuilder();
                    sb.AppendFormat("TODO");
                    prose = sb.ToString();

                    _result = wood.DoRoundover(cs, he, radius, id);

                    facesToBeLabeled.Add(_result.FindFace(sol.name, f.name));
                    facesToBeLabeled.Add(_result.FindFace(sol.name, he.Opposite().face.name));

                    break;
                }

                case Action.NEW_BOARD:
                {
                    Inches        width     = Get_Eval("width");
                    Inches        length    = Get_Eval("length");
                    Inches        thickness = Get_Eval("thickness");
                    string        newname   = Get_String("newname");
                    string        material  = Get_String("material");
                    BoardMaterial bm        = BoardMaterial.Find(material);

                    StringBuilder sb = new StringBuilder();
                    sb.AppendFormat("Cut a new board made of {0}\r\n", bm.GetProse());
                    sb.AppendFormat("{0} wide\r\n{1} long\r\n{2} thick\r\n", width.GetProse(), length.GetProse(), thickness.GetProse());
                    sb.AppendFormat("Call this board '{0}'.", newname);
                    prose = sb.ToString();

                    _result = wood.CreateBoard(bm, newname, width, length, thickness).ToCompoundSolid();

                    Face     ftop = _result.Subs[0].FindFace("top");
                    HalfEdge he   = ftop.FindEdge("end1");
                    this.annotations_PP.Add(new Annotation_PointToPoint(he.from, he.to, ftop.UnitNormal(), 2));

                    he = ftop.FindEdge("left");
                    this.annotations_PP.Add(new Annotation_PointToPoint(he.from, he.to, ftop.UnitNormal(), 2));

                    Face fend1 = _result.Subs[0].FindFace("end1");
                    he = fend1.FindEdge("left");
                    this.annotations_PP.Add(new Annotation_PointToPoint(he.from, he.to, fend1.UnitNormal(), 2));

                    this.facesToBeLabeled.AddRange(_result.Subs[0].Faces);

                    break;
                }

                case Action.JOIN:
                {
                    Inches        offset1 = Get_Eval("offset1");
                    Inches        offset2 = Get_Eval("offset2");
                    string        path1   = Get_String("path1");
                    string        path2   = Get_String("path2");
                    EdgeAlignment align   = Get_EdgeAlignment("align");

                    CompoundSolid s1;
                    CompoundSolid s2;
                    Solid         sol1;
                    Solid         sol2;
                    Face          f1;
                    Face          f2;
                    HalfEdge      he1;
                    HalfEdge      he2;

                    Lookup(path1, out s1);
                    Lookup(path2, out s2);

                    CompoundSolid snew = s1.ShallowClone();             // s1 doesn't get modified by the join, so we don't need full clone
                    CompoundSolid sadd = s2.Clone();                    // s2 gets rotated and moved, so this step needs its own copy of every subsolid

                    snew.Lookup(path1, out sol1, out f1, out he1);
                    sadd.Lookup(path2, out sol2, out f2, out he2);

                    StringBuilder sb = new StringBuilder();
                    sb.AppendFormat("Join the board named '{0}'\r\nto the board named '{1}'\r\nas follows:\r\n",
                                    sol2.name,
                                    sol1.name);
                    sb.AppendFormat("On '{0}' find the face '{1}'\r\nand the edge shared between that face and '{2}'.\r\n",
                                    sol2.name, f2.name, he2.Opposite().face.name);
                    sb.AppendFormat("On '{0}' find the face '{1}'\r\nand the edge shared between that face and '{2}'.\r\n",
                                    sol1.name, f1.name, he1.Opposite().face.name);
                    sb.AppendFormat("Join these two faces together by matching up the two edges described above");
                    // TODO align
                    if (offset1 > 0)
                    {
                        sb.AppendFormat("at an offset of {0} along the edges", offset1.GetProse());
                    }
                    if (offset2 > 0)
                    {
                        sb.AppendFormat("at an offset of {0} perpendicular to the edges", offset2.GetProse());
                    }
                    prose = sb.ToString();

                    orient.Edges(sadd, f1, f2, he1, he2, align, offset1, offset2);
                    snew.AddSub(sadd);

#if DEBUG
                    snew.AssertNoNameClashes();
#endif

                    if (!snew.IsValidWithNoSubOverlaps())
                    {
                        Errors.Add("Invalid join:  Two boards cannot occupy the same space.");
                    }

                    _result = snew;

                    facesToBeLabeled.Add(_result.FindFace(sol1.name, f1.name));
                    facesToBeLabeled.Add(_result.FindFace(sol1.name, he1.Opposite().face.name));

                    facesToBeLabeled.Add(_result.FindFace(sol2.name, f2.name));
                    facesToBeLabeled.Add(_result.FindFace(sol2.name, he2.Opposite().face.name));

                    break;
                }

                case Action.JOIN_MT:
                {
                    string path1 = Get_String("mortisepath");
                    string path2 = Get_String("tenonpath");

                    CompoundSolid s1;
                    CompoundSolid s2;
                    Solid         sol1;
                    Solid         sol2;
                    Face          f1;
                    Face          f2;
                    HalfEdge      he1;
                    HalfEdge      he2;

                    Lookup(path1, out s1);
                    Lookup(path2, out s2);

                    CompoundSolid snew = s1.ShallowClone();             // s1 doesn't get modified by the join, so we don't need full clone
                    CompoundSolid sadd = s2.Clone();                    // s2 gets rotated and moved, so this step needs its own copy of every subsolid

                    snew.Lookup(path1, out sol1, out f1, out he1);
                    sadd.Lookup(path2, out sol2, out f2, out he2);

                    StringBuilder sb = new StringBuilder();
                    sb.AppendFormat("Assemble a mortise/tenon joint\r\njoining the board named '{0}' to the board named '{1}' as follows:\r\n",
                                    sol2.name,
                                    sol1.name);
                    sb.AppendFormat(" On '{0}' find the face '{1}' and the edge shared between that face and '{2}'.",
                                    sol2.name, f2.name, he2.Opposite().face.name);
                    sb.AppendFormat(" On '{0}' find the face '{1}' and the edge shared between that face and '{2}'.",
                                    sol1.name, f1.name, he1.Opposite().face.name);
                    sb.AppendFormat(" Join these two faces together by matching up the two edges described above.");
                    prose = sb.ToString();

                    orient.Edges(sadd, f1, f2, he1, he2, EdgeAlignment.Center, 0, 0);
                    snew.AddSub(sadd);

                    // TODO verify that the gluejoint has at least 3 pairs of faces (but what about face pairs not-local to this joint?)
#if DEBUG
                    snew.AssertNoNameClashes();
#endif

                    if (!snew.IsValidWithNoSubOverlaps())
                    {
                        Errors.Add("Invalid join:  Two boards cannot occupy the same space.");
                    }

                    _result = snew;

                    facesToBeLabeled.Add(_result.FindFace(sol1.name, f1.name));
                    facesToBeLabeled.Add(_result.FindFace(sol1.name, he1.Opposite().face.name));

                    facesToBeLabeled.Add(_result.FindFace(sol2.name, f2.name));
                    facesToBeLabeled.Add(_result.FindFace(sol2.name, he2.Opposite().face.name));

                    break;
                }

                case Action.DOVETAIL_JOIN:
                {
                    string id = Get_String("id");
                    if (!plan.Dovetails.ContainsKey(id))
                    {
                        Errors.Add(string.Format("Dovetail not found: {0}", id));
                    }
                    else
                    {
                        Dovetail dt = plan.Dovetails[id];

                        CompoundSolid cs1;
                        CompoundSolid cs2;

                        Lookup(dt.path1, out cs1);
                        Lookup(dt.path2, out cs2);

                        CompoundSolid snew = cs1.Clone();
                        CompoundSolid sadd = cs2.Clone();

                        StringBuilder sb = new StringBuilder();
                        sb.AppendFormat("Assemble the dovetail joint called '{0}'\r\n",
                                        id);
                        prose = sb.ToString();

                        dt.Join(snew, sadd);

                        if (!snew.IsValidWithNoSubOverlaps())
                        {
                            Errors.Add("Invalid join:  Two boards cannot occupy the same space.");
                        }

                        _result = snew;

                        string _s1, _f1, _e1;
                        string _s2, _f2, _e2;
                        ut.ParsePath(dt.path1, out _s1, out _f1, out _e1);
                        ut.ParsePath(dt.path2, out _s2, out _f2, out _e2);

                        facesToBeLabeled.Add(_result.FindFace(_s1, _e1));
                        facesToBeLabeled.Add(_result.FindFace(_s2, _e2));
                    }
                    break;
                }

                case Action.DOVETAIL_PINS:
                {
                    string id = Get_String("id");
                    if (!plan.Dovetails.ContainsKey(id))
                    {
                        Errors.Add(string.Format("Dovetail not found: {0}", id));
                    }
                    else
                    {
                        Dovetail      dt = plan.Dovetails[id];
                        CompoundSolid cs1;
                        CompoundSolid cs2;

                        Lookup(dt.path1, out cs1);
                        Lookup(dt.path2, out cs2);

                        string s_s1, s_f1, s_e1;
                        ut.ParsePath(dt.path1, out s_s1, out s_f1, out s_e1);

                        StringBuilder sb = new StringBuilder();
                        sb.AppendFormat("For the dovetail joint called '{0}',\r\nCut the pins in the board named '{1}'\r\n",
                                        id,
                                        s_s1);
                        sb.AppendFormat("in the face named '{0}'\r\n", s_f1);
                        sb.AppendFormat("with the face named '{0}' to be the outside of the joint.", s_e1);
                        prose = sb.ToString();

                        _result = dt.Pins(cs1);

                        facesToBeLabeled.Add(_result.FindFace(s_s1, s_e1));
                    }
                    break;
                }

                case Action.DOVETAIL_TAILS:
                {
                    string id        = Get_String("id");
                    string path1     = Get_String("path1");
                    string path2     = Get_String("path2");
                    int    numtails  = Get_Eval_Integer("numtails");
                    Inches tailwidth = Get_Eval("tailwidth");
                    // TODO angle/slope

                    CompoundSolid cs1;
                    CompoundSolid cs2;
                    Solid         s1;
                    Solid         s2;
                    Face          f1;
                    Face          f2;
                    HalfEdge      he1;
                    HalfEdge      he2;

                    Lookup(Get_String("path1"), out cs1, out s1, out f1, out he1);
                    Lookup(Get_String("path2"), out cs2, out s2, out f2, out he2);

                    if (he1.face.GetQuality() != FaceQuality.EndGrain)
                    {
                        Warnings.Add("The face/edge for the tails should be endgrain");
                    }
                    if (he2.face.GetQuality() != FaceQuality.EndGrain)
                    {
                        Warnings.Add("The face/edge for the pins should be endgrain");
                    }

                    StringBuilder sb = new StringBuilder();
                    sb.AppendFormat("Begin a dovetail joint called '{0}'.\r\nCut the tails in the board named '{1}'\r\n",
                                    id,
                                    s2.name);
                    sb.AppendFormat("in the face named '{0}'\r\n", f1.name);
                    sb.AppendFormat("with the face named '{0}' to be the outside of the joint.", he1.Opposite().face.name);
                    prose = sb.ToString();

                    Dovetail dt = new Dovetail(id, path1, path2, numtails, tailwidth, cs1, s1, f1, he1, cs2, s2, f2, he2);

                    CompoundSolid newcs2 = dt.Tails(cs2);

                    this.plan.Dovetails[id] = dt;

#if DEBUG
                    newcs2.AssertNoNameClashes();
#endif

                    if (!newcs2.IsValidWithNoSubOverlaps())
                    {
                        Errors.Add("Invalid join:  Two boards cannot occupy the same space.");
                    }

                    _result = newcs2;

                    facesToBeLabeled.Add(_result.FindFace(s2.name, he2.Opposite().face.name));

                    break;
                }
                }
                Debug.Assert(prose != null);
            }
            catch (Exception e)
            {
                this.Errors.Add(e.Message);
            }

            if (_result != null)
            {
                foreach (Annotation_FaceToFace a in annotations_FF)
                {
                    Solid    s1;
                    Face     f1;
                    HalfEdge he1;

                    Solid    s2;
                    Face     f2;
                    HalfEdge he2;

                    _result.FindPath(a.path1, out s1, out f1, out he1);
                    _result.FindPath(a.path2, out s2, out f2, out he2);

                    xyz p1 = he1.Center();

                    xyz n  = f2.myPlane.n;
                    xyz p0 = f2.myPlane.pts[0];

                    xyz ptfar = p1 - f1.UnitNormal() * 1000;

                    double u  = xyz.dotsub(n, p0, p1) / xyz.dotsub(n, ptfar, p1);
                    xyz    p2 = (ptfar - p1).multiply_in_place(u).add_in_place(p1);

                    this.annotations_PP.Add(new Annotation_PointToPoint(p1, p2, -he1.GetInwardNormal(), a.offset, a.size));
                }
            }
        }
Exemple #5
0
        // this is the old API for a mortise, but it's implemented using the new one.  It is now only used by unit tests.
        public static Solid Mortise(Face f, int originpt, int otherptforaxis, double x, double y, double xsize, double ysize, Inches depth, string id)
        {
            List <xyz> a  = f.MainLoop.CollectAllVertices();
            xyz        v2 = a[otherptforaxis];
            xyz        v1 = a[originpt];
            HalfEdge   he = null;

            foreach (HalfEdge h in f.MainLoop)
            {
                if (
                    (h.from == v1) &&
                    (h.to == v2)
                    )
                {
                    he = h;
                    break;
                }
            }
            CompoundSolid cs = Mortise(f.solid.ToCompoundSolid(), he, new xy(x, y), new xyz(xsize, ysize, depth), id);

            return(cs[0]);
        }
Exemple #6
0
        public static Solid CreateBoard(BoardMaterial bm, string name, Inches width, Inches length, Inches thickness)
        {
            Solid s = new Solid(name, bm);

            double dx = width;
            double dy = length;
            double dz = thickness;

            s.AddVertex(0, 0, 0);       // 0
            s.AddVertex(dx, 0, 0);      // 1
            s.AddVertex(dx, dy, 0);     // 2
            s.AddVertex(0, dy, 0);      // 3
            s.AddVertex(0, 0, -dz);     // 4
            s.AddVertex(dx, 0, -dz);    // 5
            s.AddVertex(dx, dy, -dz);   // 6
            s.AddVertex(0, dy, -dz);    // 7

            Face top    = s.CreateFace("top", 0, 1, 2, 3);
            Face right  = s.CreateFace("right", 1, 5, 6, 2);
            Face left   = s.CreateFace("left", 0, 3, 7, 4);
            Face bottom = s.CreateFace("bottom", 7, 6, 5, 4);
            Face end1   = s.CreateFace("end1", 0, 4, 5, 1);
            Face end2   = s.CreateFace("end2", 3, 2, 6, 7);

            s.board_origin = new xyz(0, 0, 0);
            s.board_u      = new xyz(dx, 0, 0);
            s.board_v      = new xyz(0, dy, 0);
            s.board_w      = new xyz(0, 0, -dz);

            s.RecalcFacePlanes();

            return(s);
        }