private void UpdateVisionMarkers(IEnumerable <Vector3Int> visibleTiles)
    {
        ClearVisionMarkers();



        foreach (Vector3Int tilePos in visibleTiles)
        {
            GameObject visionObj = Instantiate(tileVisionMarker,
                                               HexConverter.TileCoordToCartesianCoord(tilePos, 0.1f), Quaternion.identity);
            visionMarkers.Add(visionObj);
        }

        List <Vector3Int> borderEdges = hexMap.GetEdgePositions.TileBorders((visibleTiles));

        foreach (Vector3Int edgePos in borderEdges)
        {
            EdgeAlignment orientation = HexUtility.GetEdgeAlignment(edgePos);
            float         angle       = HexUtility.anglebyEdgeAlignment[orientation];
            GameObject    edgeObj     = GameObject.Instantiate(
                edgeVisionBorder,
                HexConverter.EdgeCoordToCartesianCoord(edgePos),
                Quaternion.Euler(0, angle, 0)
                );
            visionMarkers.Add(edgeObj);
        }
    }
        private void UpdateVisionMarkers(IEnumerable <Vector3Int> visibleTiles)
        {
            foreach (GameObject g in visionMarkers)
            {
                Destroy(g);
            }
            visionMarkers.Clear();

            foreach (var tilePos in visibleTiles)
            {
                GameObject tileObj = Instantiate(tileVisionMarker, HexConverter.TileCoordToCartesianCoord(tilePos, 0.1f), Quaternion.identity);
                //0.1f = explicitly set y-Coord of the tile so it is slightly above the tiles of the map
                visionMarkers.Add(tileObj);
            }

            List <Vector3Int> borderEdges = hexMap.GetEdgePositions.TileBorders(visibleTiles);

            foreach (var edgePos in borderEdges)
            {
                EdgeAlignment orientation = HexUtility.GetEdgeAlignment(edgePos);
                float         angle       = HexUtility.anglebyEdgeAlignment[orientation];
                GameObject    edgeObj     = Instantiate(edgeVisionBorder, HexConverter.EdgeCoordToCartesianCoord(edgePos), Quaternion.Euler(0, angle, 0));
                visionMarkers.Add(edgeObj);
            }
        }
示例#3
0
        private void UpdateReachableTileVisuals(List <Tile <MyTile> > reachableTiles)
        {
            foreach (GameObject g in reachableTilesMarkers)
            {
                Destroy(g);
            }
            reachableTilesMarkers.Clear();

            foreach (Tile <MyTile> tile in reachableTiles)
            {
                GameObject tileObj = Instantiate(reachableMarker, tile.CartesianPosition, Quaternion.identity);
                tileObj.transform.position += new Vector3(0, 0.1f, 0); //0.1f = explicitly set y-Coord of the tile so it is slightly above the tiles of the map
                reachableTilesMarkers.Add(tileObj);
            }

            List <Vector3Int> borderEdges = hexMap.GetEdgePositions.TileBorders(reachableTiles);

            foreach (var edgePos in borderEdges)
            {
                EdgeAlignment orientation = HexUtility.GetEdgeAlignment(edgePos);
                float         angle       = HexUtility.anglebyEdgeAlignment[orientation];
                GameObject    edgeObj     = Instantiate(edgeReachableBorder, HexConverter.EdgeCoordToCartesianCoord(edgePos), Quaternion.Euler(0, angle, 0));
                reachableTilesMarkers.Add(edgeObj);
            }
        }
            /// <summary>
            /// returns the 2 corners adjacent to the input edge
            /// </summary>
            /// ![green = input edge , blue = result](GetCorners_AdjacentToEdge.png)
            public static List <Vector3Int> OfEdge(Vector3Int edge)
            {
                List <Vector3Int> corners     = new List <Vector3Int>();
                EdgeAlignment     orientation = HexUtility.GetEdgeAlignment(edge);

                int x = edge.x * 3;
                int y = edge.y * 3;
                int z = edge.z * 3;

                if (orientation == EdgeAlignment.ParallelToCubeX)
                {
                    Vector3Int topLeft     = new Vector3Int((x - 2) / 2, (y + 1) / 2, (z + 1) / 2);
                    Vector3Int bottomRight = new Vector3Int((x + 2) / 2, (y - 1) / 2, (z - 1) / 2);
                    corners.Add(topLeft);
                    corners.Add(bottomRight);
                }

                if (orientation == EdgeAlignment.ParallelToCubeY)
                {
                    Vector3Int top    = new Vector3Int((x - 1) / 2, (y + 2) / 2, (z - 1) / 2);
                    Vector3Int bottom = new Vector3Int((x + 1) / 2, (y - 2) / 2, (z + 1) / 2);
                    corners.Add(top);
                    corners.Add(bottom);
                }

                if (orientation == EdgeAlignment.ParallelToCubeZ)
                {
                    Vector3Int topRight   = new Vector3Int((x + 1) / 2, (y + 1) / 2, (z - 2) / 2);
                    Vector3Int bottomLeft = new Vector3Int((x - 1) / 2, (y - 1) / 2, (z + 2) / 2);
                    corners.Add(topRight);
                    corners.Add(bottomLeft);
                }
                return(corners);
            }
        public CrossingEdgeInfo(Vector2 edgeVertex1, Vector2 edgeVertex2, Vector2 crossingPoint,
            EdgeAlignment checkLineAlignment)
        {
            _egdeVertex1 = edgeVertex1;
            _edgeVertex2 = edgeVertex2;

            _alignment = checkLineAlignment;
            _crossingPoint = crossingPoint;
        }
        public CrossingEdgeInfo(Vector2 edgeVertex1, Vector2 edgeVertex2, Vector2 crossingPoint,
                                EdgeAlignment checkLineAlignment)
        {
            _egdeVertex1 = edgeVertex1;
            _edgeVertex2 = edgeVertex2;

            _alignment     = checkLineAlignment;
            _crossingPoint = crossingPoint;
        }
示例#7
0
        public AccountBarButton()
        {
            brush    = new SolidBrush(Color.Transparent);
            brushKey = new SolidBrush(Color.Empty);

            alignmentColorKey = EdgeAlignment.None;
            Padding           = new Padding(2, 0, 2, 0);

            penClose = new Pen(Color.White, 2)
            {
                StartCap = System.Drawing.Drawing2D.LineCap.Square,
                EndCap   = System.Drawing.Drawing2D.LineCap.Square,
            };
        }
            /// <summary>
            /// returns the 4 edges which are adjacent to an edge
            /// </summary>
            /// ![green = input edge , blue = result](GetEdges_AdjacentToEdge.png)
            public static List <Vector3Int> AdjacentToEdge(Vector3Int edge)
            {
                List <Vector3Int> edgeCoords   = new List <Vector3Int>();
                EdgeAlignment     orientiation = HexUtility.GetEdgeAlignment(edge);

                if (orientiation == EdgeAlignment.ParallelToCubeY)
                {
                    Vector3Int topRightEdge    = edge + new Vector3Int(0, +1, -1);
                    Vector3Int bottomRightEdge = edge + new Vector3Int(+1, -1, 0);
                    Vector3Int bottomLeftEdge  = edge + new Vector3Int(0, -1, +1);
                    Vector3Int topLeftEdge     = edge + new Vector3Int(-1, +1, 0);
                    edgeCoords.Add(topRightEdge);
                    edgeCoords.Add(bottomRightEdge);
                    edgeCoords.Add(bottomLeftEdge);
                    edgeCoords.Add(topLeftEdge);
                }
                else if (orientiation == EdgeAlignment.ParallelToCubeX)
                {
                    Vector3Int rightEdge  = edge + new Vector3Int(+1, 0, -1);
                    Vector3Int bottomEdge = edge + new Vector3Int(+1, -1, 0);
                    Vector3Int leftEdge   = edge + new Vector3Int(-1, 0, +1);
                    Vector3Int topEdge    = edge + new Vector3Int(-1, +1, 0);
                    edgeCoords.Add(rightEdge);
                    edgeCoords.Add(bottomEdge);
                    edgeCoords.Add(leftEdge);
                    edgeCoords.Add(topEdge);
                }
                else if (orientiation == EdgeAlignment.ParallelToCubeZ)
                {
                    Vector3Int rightEdge  = edge + new Vector3Int(+1, 0, -1);
                    Vector3Int bottomEdge = edge + new Vector3Int(0, -1, +1);
                    Vector3Int leftEdge   = edge + new Vector3Int(-1, 0, +1);
                    Vector3Int topEdge    = edge + new Vector3Int(0, +1, -1);
                    edgeCoords.Add(rightEdge);
                    edgeCoords.Add(bottomEdge);
                    edgeCoords.Add(leftEdge);
                    edgeCoords.Add(topEdge);
                }
                return(edgeCoords);
            }
        private static bool SplitPolygonEdge(Vertices polygon, EdgeAlignment edgeAlign, Vector2 coordInsideThePolygon,
                                             out int vertex1Index, out int vertex2Index)
        {
            List<CrossingEdgeInfo> edges;

            Vector2 slope;
            int nearestEdgeVertex1Index = 0;
            int nearestEdgeVertex2Index = 0;
            bool edgeFound = false;

            float shortestDistance = float.MaxValue;

            bool edgeCoordFound = false;
            Vector2 foundEdgeCoord = Vector2.Zero;

            vertex1Index = 0;
            vertex2Index = 0;

            switch (edgeAlign)
            {
                case EdgeAlignment.Vertical:
                    edges = GetCrossingEdges(polygon, EdgeAlignment.Vertical, (int) coordInsideThePolygon.Y);

                    foundEdgeCoord.Y = coordInsideThePolygon.Y;

                    if (edges != null && edges.Count > 1 && edges.Count%2 == 0)
                    {
                        float distance;
                        for (int i = 0; i < edges.Count; i++)
                        {
                            if (edges[i].CrossingPoint.X < coordInsideThePolygon.X)
                            {
                                distance = coordInsideThePolygon.X - edges[i].CrossingPoint.X;

                                if (distance < shortestDistance)
                                {
                                    shortestDistance = distance;
                                    foundEdgeCoord.X = edges[i].CrossingPoint.X;

                                    edgeCoordFound = true;
                                }
                            }
                        }

                        if (edgeCoordFound)
                        {
                            shortestDistance = float.MaxValue;

                            int edgeVertex2Index = polygon.Count - 1;

                            int edgeVertex1Index;
                            for (edgeVertex1Index = 0; edgeVertex1Index < polygon.Count; edgeVertex1Index++)
                            {
                                Vector2 tempVector1 = polygon[edgeVertex1Index];
                                Vector2 tempVector2 = polygon[edgeVertex2Index];
                                distance = LineTools.DistanceBetweenPointAndLineSegment(ref foundEdgeCoord,
                                                                                        ref tempVector1, ref tempVector2);
                                if (distance < shortestDistance)
                                {
                                    shortestDistance = distance;

                                    nearestEdgeVertex1Index = edgeVertex1Index;
                                    nearestEdgeVertex2Index = edgeVertex2Index;

                                    edgeFound = true;
                                }

                                edgeVertex2Index = edgeVertex1Index;
                            }

                            if (edgeFound)
                            {
                                slope = polygon[nearestEdgeVertex2Index] - polygon[nearestEdgeVertex1Index];
                                slope.Normalize();

                                Vector2 tempVector = polygon[nearestEdgeVertex1Index];
                                distance = LineTools.DistanceBetweenPointAndPoint(ref tempVector, ref foundEdgeCoord);

                                vertex1Index = nearestEdgeVertex1Index;
                                vertex2Index = nearestEdgeVertex1Index + 1;

                                polygon.Insert(nearestEdgeVertex1Index, distance*slope + polygon[vertex1Index]);
                                polygon.Insert(nearestEdgeVertex1Index, distance*slope + polygon[vertex2Index]);

                                return true;
                            }
                        }
                    }
                    break;

                case EdgeAlignment.Horizontal:
                    throw new Exception("EdgeAlignment.Horizontal isn't implemented yet. Sorry.");
            }

            return false;
        }
示例#10
0
        private static List<CrossingEdgeInfo> GetCrossingEdges(Vertices polygon, EdgeAlignment edgeAlign, int checkLine)
        {
            List<CrossingEdgeInfo> edges = new List<CrossingEdgeInfo>();

            Vector2 slope;
            Vector2 edgeVertex1;
            Vector2 edgeVertex2;

            Vector2 slopePreview;
            Vector2 edgeVertexPreview;

            Vector2 crossingPoint;
            bool addCrossingPoint;

            if (polygon.Count > 1)
            {
                edgeVertex2 = polygon[polygon.Count - 1];

                switch (edgeAlign)
                {
                    case EdgeAlignment.Vertical:
                        for (int i = 0; i < polygon.Count; i++)
                        {
                            edgeVertex1 = polygon[i];

                            if ((edgeVertex1.Y >= checkLine && edgeVertex2.Y <= checkLine) ||
                                (edgeVertex1.Y <= checkLine && edgeVertex2.Y >= checkLine))
                            {
                                if (edgeVertex1.Y != edgeVertex2.Y)
                                {
                                    addCrossingPoint = true;
                                    slope = edgeVertex2 - edgeVertex1;

                                    if (edgeVertex1.Y == checkLine)
                                    {
                                        edgeVertexPreview = polygon[(i + 1)%polygon.Count];
                                        slopePreview = edgeVertex1 - edgeVertexPreview;

                                        if (slope.Y > 0)
                                        {
                                            addCrossingPoint = (slopePreview.Y <= 0);
                                        }
                                        else
                                        {
                                            addCrossingPoint = (slopePreview.Y >= 0);
                                        }
                                    }

                                    if (addCrossingPoint)
                                    {
                                        crossingPoint =
                                            new Vector2((checkLine - edgeVertex1.Y)/slope.Y*slope.X + edgeVertex1.X,
                                                        checkLine);
                                        edges.Add(new CrossingEdgeInfo(crossingPoint,
                                                                       edgeAlign));
                                    }
                                }
                            }
                            edgeVertex2 = edgeVertex1;
                        }
                        break;

                    case EdgeAlignment.Horizontal:
                        throw new Exception("EdgeAlignment.Horizontal isn't implemented yet. Sorry.");
                }
            }

            edges.Sort();
            return edges;
        }
示例#11
0
文件: orient.cs 项目: thild/sawdust
        public static void Edges(IOrient s2, Face f1, Face f2, HalfEdge he1, HalfEdge he2, EdgeAlignment align, double offset1, double offset2, bool reversed)
        {
            xyz v1;
            xyz v2;

            xyz uv1 = (he1.to - he1.from).normalize_in_place();

            Debug.Assert(
                (align == EdgeAlignment.Center) ||
                (align == EdgeAlignment.Right) ||
                (align == EdgeAlignment.Left)
                );

            // move the solid to match up two points
            if (align == EdgeAlignment.Center)
            {
                v1 = he1.Center();
                if (!fp.eq_inches(offset1, 0))
                {
                    v1 += (offset1 * uv1);
                }
                v2 = he2.Center();
            }
            else if (align == EdgeAlignment.Right)
            {
                v1 = he1.to;
                if (!fp.eq_inches(offset1, 0))
                {
                    v1 -= (offset1 * uv1);
                }
                v2 = he2.from;
            }
            else // left
            {
                v1 = he1.from;
                if (!fp.eq_inches(offset1, 0))
                {
                    v1 += (offset1 * uv1);
                }
                v2 = he2.to;
            }

            if (!fp.eq_inches(offset2, 0))
            {
                xyz uv1perp = -(he1.GetInwardNormal());
                v1 += (offset2 * uv1perp);
            }

            xyz tv = v1 - v2;

            s2.Translate(tv.x, tv.y, tv.z);

            if (reversed)
            {
                RotateSoFacesAreParallelAndSameDir(s2, f1, f2, v1);
            }
            else
            {
                RotateSoFacesAreParallelAndOpposite(s2, f1, f2, v1);
            }

            // now rotate around origin = f1.MainLoop[0].to and vector = n1 to align the other points
            xyz q1 = he1.UnitVector();
            xyz q2 = he2.UnitVector();

            if (reversed)
            {
                q2 = -q2;
            }
            if (fp.eq_unitvec(q1, q2))
            {
                s2.Rotate(-1, 0, v1, f1.UnitNormal());
            }
            else if (fp.eq_unitvec(q1, -q2))
            {
                // do nothing.  this is perfect.
            }
            else
            {
                double dot = xyz.dot(q1, q2);
                xyz    kp  = xyz.cross(q2, q1).normalize_in_place();
                s2.Rotate(-dot, -Math.Sqrt(1 - dot * dot), v1, kp);
            }
        }
示例#12
0
文件: orient.cs 项目: thild/sawdust
 public static void Edges(IOrient s2, Face f1, Face f2, HalfEdge he1, HalfEdge he2, EdgeAlignment align, double offset1, double offset2)
 {
     Edges(s2, f1, f2, he1, he2, align, offset1, offset2, false);
 }
 public CrossingEdgeInfo(Vector2 crossingPoint, EdgeAlignment checkLineAlignment)
 {
     _alignment    = checkLineAlignment;
     CrossingPoint = crossingPoint;
 }
示例#14
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));
                }
            }
        }
示例#15
0
 public CrossingEdgeInfo(Vector2 crossingPoint, EdgeAlignment checkLineAlignment)
 {
     _alignment = checkLineAlignment;
     CrossingPoint = crossingPoint;
 }
        private static bool SplitPolygonEdge(Vertices polygon, EdgeAlignment edgeAlign, Vector2 coordInsideThePolygon,
                                             out int vertex1Index, out int vertex2Index)
        {
            List <CrossingEdgeInfo> edges;

            Vector2 slope;
            int     nearestEdgeVertex1Index = 0;
            int     nearestEdgeVertex2Index = 0;
            bool    edgeFound = false;

            float shortestDistance = float.MaxValue;

            bool    edgeCoordFound = false;
            Vector2 foundEdgeCoord = Vector2.Zero;

            vertex1Index = 0;
            vertex2Index = 0;

            switch (edgeAlign)
            {
            case EdgeAlignment.Vertical:
                edges = GetCrossingEdges(polygon, EdgeAlignment.Vertical, (int)coordInsideThePolygon.Y);

                foundEdgeCoord.Y = coordInsideThePolygon.Y;

                if (edges != null && edges.Count > 1 && edges.Count % 2 == 0)
                {
                    float distance;
                    for (int i = 0; i < edges.Count; i++)
                    {
                        if (edges[i].CrossingPoint.X < coordInsideThePolygon.X)
                        {
                            distance = coordInsideThePolygon.X - edges[i].CrossingPoint.X;

                            if (distance < shortestDistance)
                            {
                                shortestDistance = distance;
                                foundEdgeCoord.X = edges[i].CrossingPoint.X;

                                edgeCoordFound = true;
                            }
                        }
                    }

                    if (edgeCoordFound)
                    {
                        shortestDistance = float.MaxValue;

                        int edgeVertex2Index = polygon.Count - 1;

                        int edgeVertex1Index;
                        for (edgeVertex1Index = 0; edgeVertex1Index < polygon.Count; edgeVertex1Index++)
                        {
                            Vector2 tempVector1 = polygon[edgeVertex1Index];
                            Vector2 tempVector2 = polygon[edgeVertex2Index];
                            distance = LineTools.DistanceBetweenPointAndLineSegment(ref foundEdgeCoord,
                                                                                    ref tempVector1, ref tempVector2);
                            if (distance < shortestDistance)
                            {
                                shortestDistance = distance;

                                nearestEdgeVertex1Index = edgeVertex1Index;
                                nearestEdgeVertex2Index = edgeVertex2Index;

                                edgeFound = true;
                            }

                            edgeVertex2Index = edgeVertex1Index;
                        }

                        if (edgeFound)
                        {
                            slope = polygon[nearestEdgeVertex2Index] - polygon[nearestEdgeVertex1Index];
                            slope.Normalize();

                            Vector2 tempVector = polygon[nearestEdgeVertex1Index];
                            distance = LineTools.DistanceBetweenPointAndPoint(ref tempVector, ref foundEdgeCoord);

                            vertex1Index = nearestEdgeVertex1Index;
                            vertex2Index = nearestEdgeVertex1Index + 1;

                            polygon.Insert(nearestEdgeVertex1Index, distance * slope + polygon[vertex1Index]);
                            polygon.Insert(nearestEdgeVertex1Index, distance * slope + polygon[vertex2Index]);

                            return(true);
                        }
                    }
                }
                break;

            case EdgeAlignment.Horizontal:
                throw new Exception("EdgeAlignment.Horizontal isn't implemented yet. Sorry.");
            }

            return(false);
        }
        private static List <CrossingEdgeInfo> GetCrossingEdges(Vertices polygon, EdgeAlignment edgeAlign, int checkLine)
        {
            List <CrossingEdgeInfo> edges = new List <CrossingEdgeInfo>();

            Vector2 slope;
            Vector2 edgeVertex1;
            Vector2 edgeVertex2;

            Vector2 slopePreview;
            Vector2 edgeVertexPreview;

            Vector2 crossingPoint;
            bool    addCrossingPoint;

            if (polygon.Count > 1)
            {
                edgeVertex2 = polygon[polygon.Count - 1];

                switch (edgeAlign)
                {
                case EdgeAlignment.Vertical:
                    for (int i = 0; i < polygon.Count; i++)
                    {
                        edgeVertex1 = polygon[i];

                        if ((edgeVertex1.Y >= checkLine && edgeVertex2.Y <= checkLine) ||
                            (edgeVertex1.Y <= checkLine && edgeVertex2.Y >= checkLine))
                        {
                            if (edgeVertex1.Y != edgeVertex2.Y)
                            {
                                addCrossingPoint = true;
                                slope            = edgeVertex2 - edgeVertex1;

                                if (edgeVertex1.Y == checkLine)
                                {
                                    edgeVertexPreview = polygon[(i + 1) % polygon.Count];
                                    slopePreview      = edgeVertex1 - edgeVertexPreview;

                                    if (slope.Y > 0)
                                    {
                                        addCrossingPoint = (slopePreview.Y <= 0);
                                    }
                                    else
                                    {
                                        addCrossingPoint = (slopePreview.Y >= 0);
                                    }
                                }

                                if (addCrossingPoint)
                                {
                                    crossingPoint =
                                        new Vector2((checkLine - edgeVertex1.Y) / slope.Y * slope.X + edgeVertex1.X,
                                                    checkLine);
                                    edges.Add(new CrossingEdgeInfo(edgeVertex1, edgeVertex2, crossingPoint,
                                                                   edgeAlign));
                                }
                            }
                        }
                        edgeVertex2 = edgeVertex1;
                    }
                    break;

                case EdgeAlignment.Horizontal:
                    throw new Exception("EdgeAlignment.Horizontal isn't implemented yet. Sorry.");
                }
            }

            edges.Sort();
            return(edges);
        }
        /// <summary>
        /// returns an list of each contiguous border path of the input Tile Coordinates. Each individual path is ordered in clockwise direction with an arbitrary starting point. The different Paths are returned in an arbitrary order
        /// </summary>
        /// ![green = input tiles , blue = result](Map_GetEdges_BorderPaths.png)
        public List <List <Vector3Int> > BorderPaths(IEnumerable <Vector3Int> tiles, out List <List <EdgeDirection> > pathDirections)
        {
            if (coordinateWrapper == null)
            {
                return(HexGrid.GetEdges.BorderPaths(tiles, out pathDirections));
            }

            pathDirections = new List <List <EdgeDirection> >();
            List <List <Vector3Int> > borderPaths    = new List <List <Vector3Int> >();
            List <Vector3Int>         edgesUnordered = TileBorders(tiles);
            HashSet <Vector3Int>      unusedEdges    = new HashSet <Vector3Int>(edgesUnordered); //we remove every edge which we used from this collection to find out which are still left after we finished a path

            //we do it as long as we didn't use all edges because that means we didn't get all paths yet.
            while (unusedEdges.Count > 0)
            {
                List <Vector3Int>    borderPath      = new List <Vector3Int>();
                List <EdgeDirection> borderDirection = new List <EdgeDirection>();
                Vector3Int           topRightEdge    = new Vector3Int();

                //can we just use any edge instead? -> nah we want to ensure it being clockwise...

                int maxYsoFar       = int.MinValue;
                int maxXOfmaxYsoFar = int.MinValue;
                //now we pick one of the top most edges which is parallel to the X-axis of our cube
                foreach (Vector3Int edge in unusedEdges)
                {
                    EdgeAlignment orientation = HexUtility.GetEdgeAlignment(edge);
                    if (orientation != EdgeAlignment.ParallelToCubeX)
                    {
                        continue;
                    }
                    if (edge.y > maxYsoFar)
                    {
                        topRightEdge    = edge;
                        maxXOfmaxYsoFar = edge.x;
                        maxYsoFar       = edge.y;
                    }
                    else if (edge.y == maxYsoFar && edge.x > maxXOfmaxYsoFar)
                    {
                        topRightEdge    = edge;
                        maxXOfmaxYsoFar = edge.x;
                        maxYsoFar       = edge.y;
                    }
                }

                Vector3Int    currentEdge      = topRightEdge;
                EdgeDirection currentDirection = EdgeDirection.BottomRight;
                bool          targetReached    = false;
                int           safety           = 0;

                while (!targetReached)
                {
                    safety++;
                    if (safety > 250)
                    {
                        Debug.Log("safety reached!!! Error in while loop, preventing going infinite");
                        break;
                    }
                    borderPath.Add(currentEdge);
                    borderDirection.Add(currentDirection);
                    unusedEdges.Remove(currentEdge);

                    Vector3Int offsetClockwise                    = HexGrid.ClockWiseNeighbourOfEdgeByEdgeDirection[(int)currentDirection];
                    Vector3Int offsetCounterClockwise             = HexGrid.CounterClockWiseNeighbourOfEdgeByEdgeDirection[(int)currentDirection];
                    Vector3Int potentialClockwiseNeighbour        = coordinateWrapper.WrapEdgeCoordinate(currentEdge + offsetClockwise);
                    Vector3Int potentialCounterClockwiseNeighbour = coordinateWrapper.WrapEdgeCoordinate(currentEdge + offsetCounterClockwise);

                    if (unusedEdges.Contains(potentialCounterClockwiseNeighbour))
                    {
                        currentEdge      = potentialCounterClockwiseNeighbour;
                        currentDirection = (EdgeDirection)((int)(currentDirection + 5) % 6);
                    }
                    else if (unusedEdges.Contains(potentialClockwiseNeighbour))
                    {
                        currentEdge      = potentialClockwiseNeighbour;
                        currentDirection = (EdgeDirection)((int)(currentDirection + 1) % 6);
                    }
                    else //we didn't found any unused edge so we must be at end (change to flag I guess and replace do while with normal while
                    {
                        targetReached = true;
                    }
                }

                borderPaths.Add(borderPath);
                pathDirections.Add(borderDirection);
            }

            for (int i = 1; i < borderPaths.Count; i++)
            {
                borderPaths[i].Reverse();
                pathDirections[i].Reverse();
                for (int j = 0; j < pathDirections[i].Count; j++)
                {
                    pathDirections[i][j] = (EdgeDirection)(((int)pathDirections[i][j] + 3) % 6);
                }
            }
            return(borderPaths);
        }
            /// <summary>
            /// returns all the border paths of one contiguous Area. Outer path is clockwise, others are counterclockwise
            /// </summary>
            /// ![green = input tiles , blue = result](GetEdges_BorderPaths.png)
            public static List <List <Vector3Int> > BorderPaths(IEnumerable <Vector3Int> tiles, out List <List <EdgeDirection> > pathDirections)
            {
                pathDirections = new List <List <EdgeDirection> >();
                List <List <Vector3Int> > borderPaths    = new List <List <Vector3Int> >();
                List <Vector3Int>         edgesUnordered = TileBorders(tiles);
                HashSet <Vector3Int>      unusedEdges    = new HashSet <Vector3Int>(edgesUnordered); //we remove every edge which we used from this collection to find out which are still left after we finished a path

                //we do it as long as we didn't use all edges because that means we didn't get all paths yet.
                while (unusedEdges.Count > 0)
                {
                    List <Vector3Int>    borderPath      = new List <Vector3Int>();
                    List <EdgeDirection> borderDirection = new List <EdgeDirection>();
                    Vector3Int           topRightEdge    = new Vector3Int();

                    //can we just use any edge instead? -> nah we want to ensure it being clockwise...

                    int maxYsoFar       = int.MinValue;
                    int maxXOfmaxYsoFar = int.MinValue;
                    //now we pick one of the top most edges which is parallel to the X-axis of our cube
                    foreach (Vector3Int edge in unusedEdges)
                    {
                        EdgeAlignment orientation = HexUtility.GetEdgeAlignment(edge);
                        if (orientation != EdgeAlignment.ParallelToCubeX)
                        {
                            continue;
                        }
                        if (edge.y > maxYsoFar)
                        {
                            topRightEdge    = edge;
                            maxXOfmaxYsoFar = edge.x;
                            maxYsoFar       = edge.y;
                        }
                        else if (edge.y == maxYsoFar && edge.x > maxXOfmaxYsoFar)
                        {
                            topRightEdge    = edge;
                            maxXOfmaxYsoFar = edge.x;
                            maxYsoFar       = edge.y;
                        }
                    }

                    Vector3Int    currentEdge      = topRightEdge;
                    EdgeDirection currentDirection = EdgeDirection.BottomRight;
                    bool          targetReached    = false;

                    while (!targetReached)
                    {
                        borderPath.Add(currentEdge);
                        borderDirection.Add(currentDirection);
                        unusedEdges.Remove(currentEdge);

                        Vector3Int offsetClockwise        = ClockWiseNeighbourOfEdgeByEdgeDirection[(int)currentDirection];
                        Vector3Int offsetCounterClockwise = CounterClockWiseNeighbourOfEdgeByEdgeDirection[(int)currentDirection];

                        if (unusedEdges.Contains(currentEdge + offsetCounterClockwise))
                        {
                            currentEdge      = currentEdge + offsetCounterClockwise;
                            currentDirection = (EdgeDirection)((int)(currentDirection + 5) % 6);
                        }
                        else if (unusedEdges.Contains(currentEdge + offsetClockwise))
                        {
                            currentEdge      = currentEdge + offsetClockwise;
                            currentDirection = (EdgeDirection)((int)(currentDirection + 1) % 6);
                        }
                        else //we didn't find any unused edge so we must be at end
                        {
                            targetReached = true;
                        }
                    }

                    borderPaths.Add(borderPath);
                    pathDirections.Add(borderDirection);
                }

                for (int i = 1; i < borderPaths.Count; i++)
                {
                    borderPaths[i].Reverse();
                    pathDirections[i].Reverse();
                    for (int j = 0; j < pathDirections[i].Count; j++)
                    {
                        pathDirections[i][j] = (EdgeDirection)(((int)pathDirections[i][j] + 3) % 6);
                    }
                }
                return(borderPaths);
            }