Esempio n. 1
0
        private Vector2D GetCircumcenter(List <Vector3D> points)
        {
            float u_ray;

            Line2D line1 = new Line2D(points[0], points[1]);
            Line2D line2 = new Line2D(points[2], points[0]);

            // Perpendicular bisectors
            Line2D bisector1 = new Line2D(line1.GetCoordinatesAt(0.5f), line1.GetCoordinatesAt(0.5f) + line1.GetPerpendicular());
            Line2D bisector2 = new Line2D(line2.GetCoordinatesAt(0.5f), line2.GetCoordinatesAt(0.5f) + line2.GetPerpendicular());

            bisector1.GetIntersection(bisector2, out u_ray);

            return(bisector1.GetCoordinatesAt(u_ray));
        }
Esempio n. 2
0
        /// <summary>
        /// Generates a label position given a start and end point of a line. Taken (with modifications) from LineLengthLabel.Move()
        /// </summary>
        /// <param name="start">Start of the line</param>
        /// <param name="end">End of the line</param>
        /// <returns></returns>
        private Vector2D GetLabelPosition(Vector2D start, Vector2D end)
        {
            // Check if start/end point is on screen...
            Vector2D   lt           = General.Map.Renderer2D.DisplayToMap(new Vector2D(0.0, General.Interface.Display.Size.Height));
            Vector2D   rb           = General.Map.Renderer2D.DisplayToMap(new Vector2D(General.Interface.Display.Size.Width, 0.0));
            RectangleF viewport     = new RectangleF((float)lt.x, (float)lt.y, (float)(rb.x - lt.x), (float)(rb.y - lt.y));
            bool       startvisible = viewport.Contains((float)start.x, (float)start.y);
            bool       endvisible   = viewport.Contains((float)end.x, (float)end.y);

            // Do this only when one point is visible, an the other isn't
            if ((!startvisible && endvisible) || (startvisible && !endvisible))
            {
                Line2D   drawnline     = new Line2D(start, end);
                Line2D[] viewportsides = new[] {
                    new Line2D(lt, rb.x, lt.y),                     // top
                    new Line2D(lt.x, rb.y, rb.x, rb.y),             // bottom
                    new Line2D(lt, lt.x, rb.y),                     // left
                    new Line2D(rb.x, lt.y, rb.x, rb.y),             // right
                };

                foreach (Line2D side in viewportsides)
                {
                    // Modify the start point so it stays on screen
                    double u;
                    if (!startvisible && side.GetIntersection(drawnline, out u))
                    {
                        start = drawnline.GetCoordinatesAt(u);
                        break;
                    }

                    // Modify the end point so it stays on screen
                    if (!endvisible && side.GetIntersection(drawnline, out u))
                    {
                        end = drawnline.GetCoordinatesAt(u);
                        break;
                    }
                }
            }

            // Create position
            Vector2D delta = end - start;

            return(new Vector2D(start.x + delta.x * 0.5, start.y + delta.y * 0.5));
        }
Esempio n. 3
0
        //mxd
        public void DrawLine3DFloor(int x1, int y1, int x2, int y2, ref PixelColor c, PixelColor c2)
        {
            Line2D line   = new Line2D(x1, y1, x2, y2);
            float  length = line.GetLength();

            if (length < DASH_INTERVAL * 2)
            {
                DrawLineSolid(x1, y1, x2, y2, ref c2);
            }
            else
            {
                float d1 = DASH_INTERVAL / length;
                float d2 = 1.0f - d1;


                Vector2D p1 = line.GetCoordinatesAt(d1);
                Vector2D p2 = line.GetCoordinatesAt(d2);

                DrawLineSolid(x1, y1, (int)p1.x, (int)p1.y, ref c2);
                DrawLineSolid((int)p1.x, (int)p1.y, (int)p2.x, (int)p2.y, ref c);
                DrawLineSolid((int)p2.x, (int)p2.y, x2, y2, ref c2);
            }
        }
Esempio n. 4
0
        // This returns the closest coordinates ON the line
        public Vector2D NearestOnLine(Vector2D pos)
        {
            float u = Line2D.GetNearestOnLine(start.Position, end.Position, pos);

            if (u < 0f)
            {
                u = 0f;
            }
            else if (u > 1f)
            {
                u = 1f;
            }
            return(Line2D.GetCoordinatesAt(start.Position, end.Position, u));
        }
Esempio n. 5
0
        public LuaVector2D GetCoordinatesAt(float u)
        {
            Vector2D output = new Vector2D(l2d.GetCoordinatesAt(u));

            if (output.IsFinite())
            {
                return(new LuaVector2D(output));
            }
            else
            {
                throw new ScriptRuntimeException("GetCoordinatesAt() called with bad u value of "
                                                 + u +
                                                 ", (maybe you had a division by 0 somewhere?)");
            }
        }
Esempio n. 6
0
        // This returns the aligned and snapped draw position
        public static DrawnVertex GetCurrentPosition(Vector2D mousemappos, bool snaptonearest, bool snaptogrid, IRenderer2D renderer, List <DrawnVertex> points)
        {
            DrawnVertex p      = new DrawnVertex();
            Vector2D    vm     = mousemappos;
            float       vrange = BuilderPlug.Me.StitchRange / renderer.Scale;

            // Snap to nearest?
            if (snaptonearest)
            {
                // Go for all drawn points
                foreach (DrawnVertex v in points)
                {
                    if (Vector2D.DistanceSq(mousemappos, v.pos) < (vrange * vrange))
                    {
                        p.pos        = v.pos;
                        p.stitch     = true;
                        p.stitchline = true;
                        return(p);
                    }
                }

                // Try the nearest vertex
                Vertex nv = General.Map.Map.NearestVertexSquareRange(mousemappos, vrange);
                if (nv != null)
                {
                    p.pos        = nv.Position;
                    p.stitch     = true;
                    p.stitchline = true;
                    return(p);
                }

                // Try the nearest linedef
                Linedef nl = General.Map.Map.NearestLinedefRange(mousemappos, BuilderPlug.Me.StitchRange / renderer.Scale);
                if (nl != null)
                {
                    // Snap to grid?
                    if (snaptogrid)
                    {
                        // Get grid intersection coordinates
                        List <Vector2D> coords = nl.GetGridIntersections();

                        // Find nearest grid intersection
                        bool     found          = false;
                        float    found_distance = float.MaxValue;
                        Vector2D found_coord    = new Vector2D();
                        foreach (Vector2D v in coords)
                        {
                            Vector2D delta = mousemappos - v;
                            if (delta.GetLengthSq() < found_distance)
                            {
                                found_distance = delta.GetLengthSq();
                                found_coord    = v;
                                found          = true;
                            }
                        }

                        if (found)
                        {
                            // Align to the closest grid intersection
                            p.pos        = found_coord;
                            p.stitch     = true;
                            p.stitchline = true;
                            return(p);
                        }
                    }
                    else
                    {
                        // Aligned to line
                        p.pos        = nl.NearestOnLine(mousemappos);
                        p.stitch     = true;
                        p.stitchline = true;
                        return(p);
                    }
                }
            }
            else
            {
                // Always snap to the first drawn vertex so that the user can finish a complete sector without stitching
                if (points.Count > 0)
                {
                    if (Vector2D.DistanceSq(mousemappos, points[0].pos) < (vrange * vrange))
                    {
                        p.pos        = points[0].pos;
                        p.stitch     = true;
                        p.stitchline = false;
                        return(p);
                    }
                }
            }

            // if the mouse cursor is outside the map bondaries check if the line between the last set point and the
            // mouse cursor intersect any of the boundary lines. If it does, set the position to this intersection
            if (points.Count > 0 &&
                (mousemappos.x < General.Map.Config.LeftBoundary || mousemappos.x > General.Map.Config.RightBoundary ||
                 mousemappos.y > General.Map.Config.TopBoundary || mousemappos.y < General.Map.Config.BottomBoundary))
            {
                Line2D        dline             = new Line2D(mousemappos, points[points.Count - 1].pos);
                bool          foundintersection = false;
                float         u      = 0.0f;
                List <Line2D> blines = new List <Line2D>();

                // lines for left, top, right and bottom bondaries
                blines.Add(new Line2D(General.Map.Config.LeftBoundary, General.Map.Config.BottomBoundary, General.Map.Config.LeftBoundary, General.Map.Config.TopBoundary));
                blines.Add(new Line2D(General.Map.Config.LeftBoundary, General.Map.Config.TopBoundary, General.Map.Config.RightBoundary, General.Map.Config.TopBoundary));
                blines.Add(new Line2D(General.Map.Config.RightBoundary, General.Map.Config.TopBoundary, General.Map.Config.RightBoundary, General.Map.Config.BottomBoundary));
                blines.Add(new Line2D(General.Map.Config.RightBoundary, General.Map.Config.BottomBoundary, General.Map.Config.LeftBoundary, General.Map.Config.BottomBoundary));

                // check for intersections with boundaries
                for (int i = 0; i < blines.Count; i++)
                {
                    if (!foundintersection)
                    {
                        // only check for intersection if the last set point is not on the
                        // line we are checking against
                        if (blines[i].GetSideOfLine(points[points.Count - 1].pos) != 0.0f)
                        {
                            foundintersection = blines[i].GetIntersection(dline, out u);
                        }
                    }
                }

                // if there was no intersection set the position to the last set point
                if (!foundintersection)
                {
                    vm = points[points.Count - 1].pos;
                }
                else
                {
                    vm = dline.GetCoordinatesAt(u);
                }
            }


            // Snap to grid?
            if (snaptogrid)
            {
                // Aligned to grid
                p.pos = General.Map.Grid.SnappedToGrid(vm);

                // special handling
                if (p.pos.x > General.Map.Config.RightBoundary)
                {
                    p.pos.x = General.Map.Config.RightBoundary;
                }
                if (p.pos.y < General.Map.Config.BottomBoundary)
                {
                    p.pos.y = General.Map.Config.BottomBoundary;
                }
                p.stitch     = snaptonearest;
                p.stitchline = snaptonearest;
                return(p);
            }
            else
            {
                // Normal position
                p.pos        = vm;
                p.stitch     = snaptonearest;
                p.stitchline = snaptonearest;
                return(p);
            }
        }
        // This returns the aligned and snapped draw position
        public static DrawnVertex GetCurrentPosition(Vector2D mousemappos, bool snaptonearest, bool snaptogrid, bool snaptocardinal, bool usefourcardinaldirections, IRenderer2D renderer, List <DrawnVertex> points)
        {
            DrawnVertex p = new DrawnVertex();

            p.stitch       = true;                                 //mxd. Setting these to false seems to be a good way to create invalid geometry...
            p.stitchline   = true;                                 //mxd
            snaptocardinal = (snaptocardinal && points.Count > 0); //mxd. Don't snap to cardinal when there are no points

            //mxd. If snap to cardinal directions is enabled and we have points, modify mouse position
            Vector2D vm, gridoffset;

            if (snaptocardinal)
            {
                Vector2D offset = mousemappos - points[points.Count - 1].pos;

                float angle;
                if (usefourcardinaldirections)
                {
                    angle = Angle2D.DegToRad((General.ClampAngle((int)Angle2D.RadToDeg(offset.GetAngle()))) / 90 * 90 + 45);
                }
                else
                {
                    angle = Angle2D.DegToRad((General.ClampAngle((int)Angle2D.RadToDeg(offset.GetAngle()) + 22)) / 45 * 45);
                }

                offset = new Vector2D(0, -offset.GetLength()).GetRotated(angle);
                vm     = points[points.Count - 1].pos + offset;

                //mxd. We need to be snapped relative to initial position
                Vector2D prev = points[points.Count - 1].pos;
                gridoffset = prev - General.Map.Grid.SnappedToGrid(prev);
            }
            else
            {
                vm         = mousemappos;
                gridoffset = new Vector2D();
            }

            float vrange = BuilderPlug.Me.StitchRange / renderer.Scale;

            // Snap to nearest?
            if (snaptonearest)
            {
                // Go for all drawn points
                foreach (DrawnVertex v in points)
                {
                    if (Vector2D.DistanceSq(vm, v.pos) < (vrange * vrange))
                    {
                        p.pos = v.pos;
                        return(p);
                    }
                }

                // Try the nearest vertex
                Vertex nv = General.Map.Map.NearestVertexSquareRange(vm, vrange);
                if (nv != null)
                {
                    //mxd. Line angle must stay the same
                    if (snaptocardinal)
                    {
                        Line2D ourline = new Line2D(points[points.Count - 1].pos, vm);
                        if (Math.Round(ourline.GetSideOfLine(nv.Position), 1) == 0)
                        {
                            p.pos = nv.Position;
                            return(p);
                        }
                    }
                    else
                    {
                        p.pos = nv.Position;
                        return(p);
                    }
                }

                // Try the nearest linedef. mxd. We'll need much bigger stitch distance when snapping to cardinal directions
                Linedef nl = General.Map.Map.NearestLinedefRange(vm, BuilderPlug.Me.StitchRange / renderer.Scale);
                if (nl != null)
                {
                    //mxd. Line angle must stay the same
                    if (snaptocardinal)
                    {
                        Line2D   ourline      = new Line2D(points[points.Count - 1].pos, vm);
                        Line2D   nearestline  = new Line2D(nl.Start.Position, nl.End.Position);
                        Vector2D intersection = Line2D.GetIntersectionPoint(nearestline, ourline, false);
                        if (!float.IsNaN(intersection.x))
                        {
                            // Intersection is on nearestline?
                            float u = Line2D.GetNearestOnLine(nearestline.v1, nearestline.v2, intersection);

                            if (u < 0f || u > 1f)
                            {
                            }
                            else
                            {
                                p.pos = new Vector2D((float)Math.Round(intersection.x, General.Map.FormatInterface.VertexDecimals),
                                                     (float)Math.Round(intersection.y, General.Map.FormatInterface.VertexDecimals));
                                return(p);
                            }
                        }
                    }
                    // Snap to grid?
                    else if (snaptogrid)
                    {
                        // Get grid intersection coordinates
                        List <Vector2D> coords = nl.GetGridIntersections(General.Map.Grid.GridRotate,
                                                                         General.Map.Grid.GridOriginX, General.Map.Grid.GridOriginY);

                        // Find nearest grid intersection
                        bool     found          = false;
                        float    found_distance = float.MaxValue;
                        Vector2D found_coord    = new Vector2D();
                        foreach (Vector2D v in coords)
                        {
                            Vector2D delta = vm - v;
                            if (delta.GetLengthSq() < found_distance)
                            {
                                found_distance = delta.GetLengthSq();
                                found_coord    = v;
                                found          = true;
                            }
                        }

                        if (found)
                        {
                            // Align to the closest grid intersection
                            p.pos = found_coord;
                            return(p);
                        }
                    }
                    else
                    {
                        // Aligned to line
                        p.pos = nl.NearestOnLine(vm);
                        return(p);
                    }
                }
            }
            else
            {
                // Always snap to the first drawn vertex so that the user can finish a complete sector without stitching
                if (points.Count > 0)
                {
                    if (Vector2D.DistanceSq(vm, points[0].pos) < (vrange * vrange))
                    {
                        p.pos = points[0].pos;
                        return(p);
                    }
                }
            }

            // if the mouse cursor is outside the map bondaries check if the line between the last set point and the
            // mouse cursor intersect any of the boundary lines. If it does, set the position to this intersection
            if (points.Count > 0 &&
                (mousemappos.x < General.Map.Config.LeftBoundary || mousemappos.x > General.Map.Config.RightBoundary ||
                 mousemappos.y > General.Map.Config.TopBoundary || mousemappos.y < General.Map.Config.BottomBoundary))
            {
                Line2D        dline             = new Line2D(mousemappos, points[points.Count - 1].pos);
                bool          foundintersection = false;
                float         u      = 0.0f;
                List <Line2D> blines = new List <Line2D>();

                // lines for left, top, right and bottom boundaries
                blines.Add(new Line2D(General.Map.Config.LeftBoundary, General.Map.Config.BottomBoundary, General.Map.Config.LeftBoundary, General.Map.Config.TopBoundary));
                blines.Add(new Line2D(General.Map.Config.LeftBoundary, General.Map.Config.TopBoundary, General.Map.Config.RightBoundary, General.Map.Config.TopBoundary));
                blines.Add(new Line2D(General.Map.Config.RightBoundary, General.Map.Config.TopBoundary, General.Map.Config.RightBoundary, General.Map.Config.BottomBoundary));
                blines.Add(new Line2D(General.Map.Config.RightBoundary, General.Map.Config.BottomBoundary, General.Map.Config.LeftBoundary, General.Map.Config.BottomBoundary));

                // check for intersections with boundaries
                for (int i = 0; i < blines.Count; i++)
                {
                    if (!foundintersection)
                    {
                        // only check for intersection if the last set point is not on the
                        // line we are checking against
                        if (blines[i].GetSideOfLine(points[points.Count - 1].pos) != 0.0f)
                        {
                            foundintersection = blines[i].GetIntersection(dline, out u);
                        }
                    }
                }

                // if there was no intersection set the position to the last set point
                if (!foundintersection)
                {
                    vm = points[points.Count - 1].pos;
                }
                else
                {
                    vm = dline.GetCoordinatesAt(u);
                }
            }

            // Snap to grid?
            if (snaptogrid)
            {
                // Aligned to grid
                p.pos = General.Map.Grid.SnappedToGrid(vm - gridoffset) + gridoffset;

                // special handling
                if (p.pos.x > General.Map.Config.RightBoundary)
                {
                    p.pos.x = General.Map.Config.RightBoundary;
                }
                if (p.pos.y < General.Map.Config.BottomBoundary)
                {
                    p.pos.y = General.Map.Config.BottomBoundary;
                }

                return(p);
            }
            else
            {
                // Normal position
                p.pos.x = (float)Math.Round(vm.x);                 //mxd
                p.pos.y = (float)Math.Round(vm.y);                 //mxd

                return(p);
            }
        }
        /// <summary>
        /// Applies the slopes to the sectors.
        ///
        /// We have:
        /// - theta
        /// - offset angle ("offset")
        /// - horizontal line length ("length")
        ///
        /// What we need to compute:
        /// - x coordinate where the line starts in the circle ("left", this is cos(theta + offset angle))
        /// - x coordinate where the line ends in the circle ("middle", this is cos(offset angle))
        ///
        /// With this data we can calculate some more required variables:
        /// - radius: length / (middle - left)
        /// - left delimiter: cos(offset + theta) * radius
        /// - right delimiter: cos(rotation) * radius (should be same as left delimiter + length)
        /// - section start, in map units: cos(offset + theta) * radius
        /// - base height offset (where the slope starts)
        ///
        /// Then we can simply use pythagoras to compute the y position for an x position on the length
        /// </summary>
        public void ApplySlope()
        {
            double left   = Math.Cos(theta + offsetangle);
            double middle = Math.Cos(offsetangle);

            double radius         = length / (middle - left);
            double leftdelimiter  = Math.Cos(offsetangle + theta);
            double rightdelimiter = Math.Cos(offsetangle);

            double sectionstart = Math.Cos(offsetangle + theta) * radius;

            baseheightoffset = Math.Sqrt(radius * radius - sectionstart * sectionstart) * scale;

            foreach (BaseVisualGeometrySector bvgs in sectors)
            {
                HashSet <Vertex> vertices = new HashSet <Vertex>(bvgs.Sector.Sides.Count * 2);
                double           u1       = 1.0;
                double           u2       = 0.0;

                foreach (Sidedef sd in bvgs.Sector.Sides.Keys)
                {
                    vertices.Add(sd.Line.Start);
                    vertices.Add(sd.Line.End);
                }

                // Get the two points that are the furthest apart on the line between the slope handles
                foreach (Vertex v in vertices)
                {
                    double intersection = handleline.GetNearestOnLine(v.Position);

                    if (intersection < u1)
                    {
                        u1 = intersection;
                    }
                    if (intersection > u2)
                    {
                        u2 = intersection;
                    }
                }

                // Compute the x position and the corrosponding height of the coordinates
                double xpos1   = sectionstart + (u1 * length);
                double xpos2   = sectionstart + (u2 * length);
                double height1 = Math.Sqrt(radius * radius - xpos1 * xpos1) * scale;
                double height2 = Math.Sqrt(radius * radius - xpos2 * xpos2) * scale;

                if (double.IsNaN(height1))
                {
                    height1 = 0.0;
                }

                if (double.IsNaN(height2))
                {
                    height2 = 0.0;
                }

                // Adjust the heights
                height1 = height1 - baseheightoffset + baseheight + heightoffset;
                height2 = height2 - baseheightoffset + baseheight + heightoffset;

                // Get the angle of the slope. We cheat a bit and substitute the y value of the vectors with the height of the points
                double slopeangle = Vector2D.GetAngle(new Vector2D(xpos1, height1), new Vector2D(xpos2, height2));

                // Always let the plane point up, VisualSidedefSlope.ApplySlope will invert it if necessary
                Plane plane = new Plane(new Vector3D(handleline.GetCoordinatesAt(u1), height1), handleline.GetAngle() + Angle2D.PIHALF, slopeangle, true);

                VisualSidedefSlope.ApplySlope(bvgs.Level, plane, mode);

                bvgs.Sector.UpdateSectorGeometry(true);
            }
        }
        //mxd. This moves the label so it stays on screen and offsets it vertically so it doesn't overlap the line
        public virtual void Move(Vector2D start, Vector2D end)
        {
            // Store before making any adjustments to start/end...
            this.start = start;
            this.end   = end;

            // Update text label
            UpdateText();

            // Check if start/end point is on screen...
            Vector2D   lt           = General.Map.Renderer2D.DisplayToMap(new Vector2D(0.0f, General.Interface.Display.Size.Height));
            Vector2D   rb           = General.Map.Renderer2D.DisplayToMap(new Vector2D(General.Interface.Display.Size.Width, 0.0f));
            RectangleF viewport     = new RectangleF(lt.x, lt.y, rb.x - lt.x, rb.y - lt.y);
            bool       startvisible = viewport.Contains(start.x, start.y);
            bool       endvisible   = viewport.Contains(end.x, end.y);

            // Do this only when one point is visible, an the other isn't
            if ((!startvisible && endvisible) || (startvisible && !endvisible))
            {
                Line2D   drawnline     = new Line2D(start, end);
                Line2D[] viewportsides = new[] {
                    new Line2D(lt, rb.x, lt.y),                     // top
                    new Line2D(lt.x, rb.y, rb.x, rb.y),             // bottom
                    new Line2D(lt, lt.x, rb.y),                     // left
                    new Line2D(rb.x, lt.y, rb.x, rb.y),             // right
                };

                foreach (Line2D side in viewportsides)
                {
                    // Modify the start point so it stays on screen
                    float u;
                    if (!startvisible && side.GetIntersection(drawnline, out u))
                    {
                        start = drawnline.GetCoordinatesAt(u);
                        break;
                    }

                    // Modify the end point so it stays on screen
                    if (!endvisible && side.GetIntersection(drawnline, out u))
                    {
                        end = drawnline.GetCoordinatesAt(u);
                        break;
                    }
                }
            }

            // Update label position
            if (offsetposition)
            {
                Vector2D perpendicular = (end - start).GetPerpendicular();
                float    angle         = perpendicular.GetAngle();
                SizeF    textsize      = General.Interface.MeasureString(label.Text, label.Font);
                float    offset        = textsize.Width * Math.Abs((float)Math.Sin(angle)) + textsize.Height * Math.Abs((float)Math.Cos(angle));
                perpendicular = perpendicular.GetNormal().GetScaled(offset / 2.0f / General.Map.Renderer2D.Scale);
                start        += perpendicular;
                end          += perpendicular;
            }

            // Apply changes
            Vector2D delta = end - start;

            label.Location = new Vector2D(start.x + delta.x * 0.5f, start.y + delta.y * 0.5f);
        }
Esempio n. 10
0
        //mxd
        public override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            // Anything to do?
            if ((!selectpressed && !editpressed) || closestline == null)
            {
                hintlabel.Text = string.Empty;
                return;
            }

            // Do something...
            Vector2D perpendicular = closestline.Line.GetPerpendicular().GetNormal();

            if (panel.Distance != 0)
            {
                perpendicular *= panel.Distance;                                 // Special cases...
            }
            Vector2D center         = closestline.GetCenterPoint();
            Line2D   radius         = new Line2D(center, center - perpendicular);
            float    u              = radius.GetNearestOnLine(mousemappos - mousedownoffset);
            int      dist           = (panel.Distance == 0 ? 1 : panel.Distance); // Special cases...
            int      offset         = (int)Math.Round(dist * u - dist);
            bool     updaterequired = false;

            // Clamp values?
            bool clampvalue = !General.Interface.ShiftState;

            // Change verts amount
            if (selectpressed && editpressed)
            {
                if (prevoffset != 0)
                {
                    // Set new verts count without triggering the update...
                    panel.SetValues(panel.Vertices + Math.Sign(prevoffset - offset), panel.Distance, panel.Angle, panel.FixedCurve);

                    // Update hint text
                    hintlabel.Text = "Vertices: " + panel.Vertices;
                    updaterequired = true;
                }
            }
            // Change distance
            else if (selectpressed && !panel.FixedCurve)
            {
                if (float.IsNaN(u))
                {
                    // Set new distance without triggering the update...
                    panel.SetValues(panel.Vertices, 0, panel.Angle, panel.FixedCurve);                     // Special cases...
                }
                else
                {
                    int newoffset;
                    if (clampvalue)
                    {
                        newoffset = (panel.Distance + offset) / panel.DistanceIncrement * panel.DistanceIncrement;                         // Clamp to 8 mu increments
                    }
                    else
                    {
                        newoffset = panel.Distance + offset;
                    }

                    // Set new distance without triggering the update...
                    panel.SetValues(panel.Vertices, newoffset, panel.Angle, panel.FixedCurve);
                }

                // Update hint text
                hintlabel.Text = "Distance: " + panel.Distance;
                updaterequired = true;
            }
            // Change angle
            else if (editpressed && prevoffset != 0)
            {
                int newangle = 0;
                if (panel.FixedCurve)
                {
                    // Flip required?
                    if (panel.Angle == 0 && (Math.Sign(offset - prevoffset) != Math.Sign(panel.Distance)))
                    {
                        // Set new distance without triggering the update...
                        panel.SetValues(panel.Vertices, -panel.Distance, panel.Angle, panel.FixedCurve);

                        // Recalculate affected values...
                        perpendicular *= -1;
                        radius.v2      = center - perpendicular;
                        u              = radius.GetNearestOnLine(mousemappos - mousedownoffset);
                    }

                    //TODO: there surely is a way to get new angle without iteration...
                    float targetoffset = radius.GetLength() * u;
                    float prevdiff     = float.MaxValue;
                    int   increment    = (clampvalue ? panel.AngleIncrement : 1);
                    for (int i = 1; i < panel.MaximumAngle; i += increment)
                    {
                        // Calculate diameter for current angle...
                        float ma = Angle2D.DegToRad(i);
                        float d  = (closestline.Length / (float)Math.Tan(ma / 2f)) / 2;
                        float D  = d / (float)Math.Cos(ma / 2f);
                        float h  = D - d;

                        float curdiff = Math.Abs(h - targetoffset);

                        // This one matches better...
                        if (curdiff < prevdiff)
                        {
                            newangle = i;
                        }
                        prevdiff = curdiff;
                    }

                    // Clamp to 5 deg increments
                    if (clampvalue)
                    {
                        newangle = (newangle / panel.AngleIncrement) * panel.AngleIncrement;
                    }
                }
                else
                {
                    int diff = (int)Math.Round((offset - prevoffset) * renderer.Scale);
                    if (panel.Angle + diff > 0)
                    {
                        if (clampvalue)
                        {
                            newangle = (panel.Angle / panel.AngleIncrement + Math.Sign(diff)) * panel.AngleIncrement;                                    // Clamp to 5 deg increments
                        }
                        else
                        {
                            newangle = panel.Angle + diff;
                        }
                    }
                }

                // Set new angle without triggering the update...
                panel.SetValues(panel.Vertices, panel.Distance, newangle, panel.FixedCurve);

                // Update hint text
                hintlabel.Text = "Angle: " + panel.Angle;
                updaterequired = true;
            }

            // Update UI
            if (updaterequired)
            {
                // Update label position
                float labeldistance;

                if (panel.Angle == 0)
                {
                    labeldistance = 0;                     // Special cases!
                }
                else if (panel.FixedCurve)
                {
                    float ma = Angle2D.DegToRad(panel.Angle);
                    float d  = (closestline.Length / (float)Math.Tan(ma / 2f)) / 2;
                    float D  = d / (float)Math.Cos(ma / 2f);
                    labeldistance = D - d;
                }
                else
                {
                    labeldistance = Math.Abs(panel.Distance);
                }

                labeldistance += 16 / renderer.Scale;
                Vector2D labelpos = radius.GetCoordinatesAt(labeldistance / radius.GetLength());
                hintlabel.Move(labelpos, labelpos);

                // Trigger update
                OnValuesChanged(null, EventArgs.Empty);
            }

            // Store current offset
            prevoffset = offset;
        }
 public Vector2 GetCoordinatesAt(float u)
 {
     return(Line2D.GetCoordinatesAt(v1, v2, u));
 }
Esempio n. 12
0
    // This finds the cut coordinates and splits the other poly with inner vertices
    private static void SplitOuterWithInner(LinkedListNode <EarClipVertex> start, EarClipPolygon p)
    {
        LinkedListNode <EarClipVertex> insertbefore = null;
        float    foundu   = float.MaxValue;
        Vector2D foundpos = new Vector2D();

        // Create a line from start that goes beyond the right most vertex of p
        LinkedListNode <EarClipVertex> pr = FindRightMostVertex(p);
        float  startx       = start.Value.Position.x;
        float  endx         = pr.Value.Position.x + 10.0f;
        Line2D starttoright = new Line2D(start.Value.Position, new Vector2D(endx, start.Value.Position.y));

        // Calculate a small bonus (0.1 mappixel)
        float bonus = starttoright.GetNearestOnLine(new Vector2D(start.Value.Position.x + 0.1f, start.Value.Position.y));

        // Go for all lines in the outer polygon
        LinkedListNode <EarClipVertex> v1 = p.Last;
        LinkedListNode <EarClipVertex> v2 = p.First;

        while (v2 != null)
        {
            // Check if the line goes between startx and endx
            if ((v1.Value.Position.x > startx || v2.Value.Position.x > startx) &&
                (v1.Value.Position.x < endx || v2.Value.Position.x < endx))
            {
                // Find intersection
                Line2D pl = new Line2D(v1.Value.Position, v2.Value.Position);
                float  u, ul;
                pl.GetIntersection(starttoright, out u, out ul);
                if (float.IsNaN(u))
                {
                    // We have found a line that is perfectly horizontal
                    // (parallel to the cut scan line) Check if the line
                    // is overlapping the cut scan line.
                    if (v1.Value.Position.y == start.Value.Position.y)
                    {
                        // This is an exceptional situation which causes a bit of a problem, because
                        // this could be a previously made cut, which overlaps another line from the
                        // same cut and we have to determine which of the two we will join with. If we
                        // pick the wrong one, the polygon is no longer valid and triangulation will fail.

                        // Calculate distance of each vertex in units
                        u  = starttoright.GetNearestOnLine(v1.Value.Position);
                        ul = starttoright.GetNearestOnLine(v2.Value.Position);

                        // Rule out vertices before the scan line
                        if (u < 0.0f)
                        {
                            u = float.MaxValue;
                        }
                        if (ul < 0.0f)
                        {
                            ul = float.MaxValue;
                        }

                        float    insert_u = Math.Min(u, ul);
                        Vector2D inserpos = starttoright.GetCoordinatesAt(insert_u);

                        // Check in which direction the line goes.
                        if (v1.Value.Position.x > v2.Value.Position.x)
                        {
                            // The line goes from right to left (towards our start point)
                            // so we must always insert our cut after this line.

                            // If the next line goes up, we consider this a better candidate than
                            // a horizontal line that goes from left to right (the other cut line)
                            // so we give it a small bonus.
                            LinkedListNode <EarClipVertex> v3 = v2.Next ?? v2.List.First;
                            if (v3.Value.Position.y < v2.Value.Position.y)
                            {
                                insert_u -= bonus;
                            }

                            // Remember this when it is a closer match
                            if (insert_u <= foundu)
                            {
                                insertbefore = v2.Next ?? v2.List.First;
                                foundu       = insert_u;
                                foundpos     = inserpos;
                            }
                        }
                        else
                        {
                            // The line goes from left to right (away from our start point)
                            // so we must always insert our cut before this line.

                            // If the previous line goes down, we consider this a better candidate than
                            // a horizontal line that goes from right to left (the other cut line)
                            // so we give it a small bonus.
                            LinkedListNode <EarClipVertex> v3 = v1.Previous ?? v1.List.Last;
                            if (v3.Value.Position.y > v1.Value.Position.y)
                            {
                                insert_u -= bonus;
                            }

                            // Remember this when it is a closer match
                            if (insert_u <= foundu)
                            {
                                insertbefore = v2;
                                foundu       = insert_u;
                                foundpos     = inserpos;
                            }
                        }
                    }
                }
                // Found a closer match?
                else if ((ul >= 0.0f) && (ul <= 1.0f) && (u > 0.0f) && (u <= foundu))
                {
                    // Found a closer intersection
                    insertbefore = v2;
                    foundu       = u;
                    foundpos     = starttoright.GetCoordinatesAt(u);
                }
            }

            // Next
            v1 = v2;
            v2 = v2.Next;
        }

        // Found anything?
        if (insertbefore != null)
        {
            Sidedef sd = (insertbefore.Previous == null) ? insertbefore.List.Last.Value.Sidedef : insertbefore.Previous.Value.Sidedef;

            // Find the position where we have to split the outer polygon
            EarClipVertex split = new EarClipVertex(foundpos, null);

            // Insert manual split vertices
            p.AddBefore(insertbefore, new EarClipVertex(split, sd));

            // Start inserting from the start (do I make sense this time?)
            v1 = start;
            do
            {
                // Insert inner polygon vertex
                p.AddBefore(insertbefore, new EarClipVertex(v1.Value));
                v1 = (v1.Next ?? v1.List.First);
            } while (v1 != start);

            // Insert manual split vertices
            p.AddBefore(insertbefore, new EarClipVertex(start.Value, sd));
            if (split.Position != insertbefore.Value.Position)
            {
                p.AddBefore(insertbefore, new EarClipVertex(split, sd));
            }
        }
    }
		// This generates the vertices to split the line with, from start to end
		private List<Vector2D> GenerateCurve(Line2D line, int vertices, float angle, bool backwards, float distance, bool fixedcurve)
		{

			// Make list
			List<Vector2D> points = new List<Vector2D>(vertices);

			//Added by Anders Åstrand 2008-05-18
			//The formulas used are taken from http://mathworld.wolfram.com/CircularSegment.html
			//c and theta are known (length of line and angle parameter). d, R and h are
			//calculated from those two
			//If the curve is not supposed to be a circular segment it's simply deformed to fit
			//the value set for distance.

			//The vertices are generated to be evenly distributed (by angle) along the curve
			//and lastly they are rotated and moved to fit with the original line

			//calculate some identities of a circle segment (refer to the graph in the url above)
			double c = line.GetLength();
			double theta = angle;

			double d = (c / Math.Tan(theta / 2)) / 2;
			double R = d / Math.Cos(theta / 2);
			double h = R - d;

			double yDeform = fixedcurve ? 1 : distance / h;
			if (backwards)
				yDeform = -yDeform;

			double a, x, y;
			Vector2D vertex;

			for (int v = 1; v <= vertices; v++)
			{
				//calculate the angle for this vertex
				//the curve starts at PI/2 - theta/2 and is segmented into vertices+1 segments
				//this assumes the line is horisontal and on y = 0, the point is rotated and moved later

				a = (Math.PI - theta) / 2 + v * (theta / (vertices + 1));

				//calculate the coordinates of the point, and distort the y coordinate
				//using the deform factor calculated above
				x = Math.Cos(a) * R;
				y = (Math.Sin(a) * R - d) * yDeform;

				//rotate and transform to fit original line
				vertex = new Vector2D((float)x, (float)y).GetRotated(line.GetAngle() + Angle2D.PIHALF);
				vertex = vertex.GetTransformed(line.GetCoordinatesAt(0.5f).x, line.GetCoordinatesAt(0.5f).y, 1, 1);

				points.Add(vertex);
			}


			// Done
			return points;
		}
		private void InitializeCatmullRomSplines()
		{
			List<Linedef> sourceld = new List<Linedef>(General.Map.Map.GetSelectedLinedefs(true));
			Line2D innerline, outerline;
			CatmullRomSplineData innerspline, outerspline;
			CatmullRomSplineGroup splinegroup;
			
			numcontrolpoints = stairsectorbuilderform.NumControlPoints;

			if (General.Map.Map.GetSelectedLinedefs(true).Count <= 0)
			{
				return;
			}

			if (catmullromsplinegroups == null)
				catmullromsplinegroups = new List<CatmullRomSplineGroup>();
			else
				catmullromsplinegroups.Clear();

			for (int l1 = 0; l1 < sourceld.Count - 1; l1++)
			{
				int l2 = l1 + 1;
				Vector2D s1, s2, e1, e2;

				s1 = stairsectorbuilderform.Flipping == 1 ? sourceld[l1].End.Position : sourceld[l1].Start.Position;
				e1 = stairsectorbuilderform.Flipping == 1 ? sourceld[l1].Start.Position : sourceld[l1].End.Position;
				s2 = stairsectorbuilderform.Flipping == 2 ? sourceld[l2].End.Position : sourceld[l2].Start.Position;
				e2 = stairsectorbuilderform.Flipping == 2 ? sourceld[l2].Start.Position : sourceld[l2].End.Position;

				//innerline = new Line2D(sourceld[l2].Start.Position, sourceld[l1].Start.Position);
				//outerline = new Line2D(sourceld[l1].End.Position, sourceld[l2].End.Position);

				innerline = new Line2D(s2, s1);
				outerline = new Line2D(e1, e2);

				innerspline = new CatmullRomSplineData();
				innerspline.controlpoints = new List<Vector2D>();

				innerspline.line = innerline;
				innerspline.controlpoints.Add(new Vector2D(innerline.v1));

				for (int k = 1; k <= numcontrolpoints - 2; k++)
					innerspline.controlpoints.Add(new Vector2D(innerline.GetCoordinatesAt(1.0f / (numcontrolpoints - 1) * k)));

				innerspline.controlpoints.Add(new Vector2D(innerline.v2));

				ComputeTangents(ref innerspline);

				outerspline = new CatmullRomSplineData();
				outerspline.controlpoints = new List<Vector2D>();

				outerspline.line = outerline;
				outerspline.controlpoints.Add(new Vector2D(outerline.v1));

				for (int k = 1; k <= numcontrolpoints - 2; k++)
					outerspline.controlpoints.Add(new Vector2D(outerline.GetCoordinatesAt(1.0f / (numcontrolpoints - 1) * k)));

				outerspline.controlpoints.Add(new Vector2D(outerline.v2));

				ComputeTangents(ref outerspline);

				splinegroup = new CatmullRomSplineGroup();
				splinegroup.splines = new CatmullRomSplineData[2];
				splinegroup.splines[INNER_SPLINE] = innerspline;
				splinegroup.splines[OUTER_SPLINE] = outerspline;
				splinegroup.sourcelinedef = sourceld[l1];

				catmullromsplinegroups.Add(splinegroup);
			}
		}