Esempio n. 1
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. 2
0
        // This updates the selection
        private void Update()
        {
            // Not in any modifying mode?
            if (mode == ModifyMode.None)
            {
                Vector2D prevdragoffset = alignoffset;
                alignoffset     = new Vector2D(float.MinValue, float.MinValue);
                showalignoffset = false;

                // Check what grip the mouse is over
                // and change cursor accordingly
                Grip mousegrip = CheckMouseGrip();
                switch (mousegrip)
                {
                case Grip.Main:
                    int   closestcorner = -1;
                    float cornerdist    = float.MaxValue;
                    for (int i = 0; i < 4; i++)
                    {
                        Vector2D delta = corners[i] - mousemappos;
                        float    d     = delta.GetLengthSq();
                        if (d < cornerdist)
                        {
                            closestcorner = i;
                            cornerdist    = d;
                        }
                    }
                    switch (closestcorner)
                    {
                    // TODO:
                    case 0: alignoffset = new Vector2D(0f, 0f); break;

                    case 1: alignoffset = new Vector2D(texture.ScaledWidth, 0f); break;

                    case 2: alignoffset = new Vector2D(texture.ScaledWidth, -texture.ScaledHeight); break;

                    case 3: alignoffset = new Vector2D(0f, -texture.ScaledHeight); break;
                    }
                    showalignoffset = true;
                    General.Interface.SetCursor(Cursors.Hand);
                    break;

                case Grip.RotateLB:
                case Grip.RotateRT:
                    alignoffset     = new Vector2D(0f, 0f);
                    showalignoffset = true;
                    General.Interface.SetCursor(Cursors.Cross);
                    break;

                case Grip.SizeH:
                case Grip.SizeV:
                    alignoffset     = new Vector2D(0f, 0f);
                    showalignoffset = true;
                    // Pick the best matching cursor depending on rotation and side
                    float resizeangle = -(rotation + sectorinfo[0].rotation);
                    if (mousegrip == Grip.SizeH)
                    {
                        resizeangle += Angle2D.PIHALF;
                    }
                    resizeangle = Angle2D.Normalized(resizeangle);
                    if (resizeangle > Angle2D.PI)
                    {
                        resizeangle -= Angle2D.PI;
                    }
                    resizeangle = Math.Abs(resizeangle + Angle2D.PI / 8.000001f);
                    int cursorindex = (int)Math.Floor((resizeangle / Angle2D.PI) * 4.0f) % 4;
                    General.Interface.SetCursor(RESIZE_CURSORS[cursorindex]);
                    break;

                default:
                    General.Interface.SetCursor(Cursors.Default);
                    break;
                }

                if (prevdragoffset != alignoffset)
                {
                    General.Interface.RedrawDisplay();
                }
            }
            else
            {
                Vector2D snappedmappos = mousemappos;
                bool     dosnaptogrid  = snaptogrid;

                // Options
                snaptogrid    = General.Interface.ShiftState ^ General.Interface.SnapToGrid;
                snaptonearest = General.Interface.CtrlState ^ General.Interface.AutoMerge;

                // Change to crosshair cursor so we can clearly see around the mouse cursor
                General.Interface.SetCursor(Cursors.Cross);

                // Check what modifying mode we are in
                switch (mode)
                {
                case ModifyMode.Dragging:

                    offset = -mousemappos - dragoffset;
                    Vector2D transformedpos = TexToWorld(alignoffset);

                    // Snap to nearest vertex?
                    if (snaptonearest)
                    {
                        float vrange = BuilderPlug.Me.StitchRange / renderer.Scale;

                        // Try the nearest vertex
                        Vertex nv = MapSet.NearestVertexSquareRange(General.Map.Map.Vertices, transformedpos, vrange);
                        if (nv != null)
                        {
                            // Change offset to snap to target
                            offset      -= nv.Position - transformedpos;
                            dosnaptogrid = false;
                        }
                        else
                        {
                            // Find the nearest line within range
                            Linedef nl = MapSet.NearestLinedefRange(General.Map.Map.Linedefs, transformedpos, vrange);
                            if (nl != null)
                            {
                                // Snap to grid?
                                if (dosnaptogrid)
                                {
                                    // Get grid intersection coordinates
                                    List <Vector2D> coords = nl.GetGridIntersections();

                                    // Find nearest grid intersection
                                    float    found_distance = float.MaxValue;
                                    Vector2D found_pos      = new Vector2D(float.NaN, float.NaN);
                                    foreach (Vector2D v in coords)
                                    {
                                        Vector2D dist = transformedpos - v;
                                        if (dist.GetLengthSq() < found_distance)
                                        {
                                            // Found a better match
                                            found_distance = dist.GetLengthSq();
                                            found_pos      = v;

                                            // Do not snap to grid anymore
                                            dosnaptogrid = false;
                                        }
                                    }

                                    // Found something?
                                    if (!float.IsNaN(found_pos.x))
                                    {
                                        // Change offset to snap to target
                                        offset -= found_pos - transformedpos;
                                    }
                                }
                                else
                                {
                                    // Change offset to snap onto the line
                                    offset -= nl.NearestOnLine(transformedpos) - transformedpos;
                                }
                            }
                        }
                    }

                    // Snap to grid?
                    if (dosnaptogrid)
                    {
                        // Change offset to align to grid
                        offset -= General.Map.Grid.SnappedToGrid(transformedpos) - transformedpos;
                    }

                    break;

                case ModifyMode.Resizing:

                    // Snap to nearest vertex?
                    if (snaptonearest)
                    {
                        float vrange = BuilderPlug.Me.StitchRange / renderer.Scale;

                        // Try the nearest vertex
                        Vertex nv = MapSet.NearestVertexSquareRange(General.Map.Map.Vertices, snappedmappos, vrange);
                        if (nv != null)
                        {
                            snappedmappos = nv.Position;
                            dosnaptogrid  = false;
                        }
                    }

                    // Snap to grid?
                    if (dosnaptogrid)
                    {
                        // Aligned to grid
                        snappedmappos = General.Map.Grid.SnappedToGrid(snappedmappos);
                    }

                    float newscale = 1f / resizeaxis.GetNearestOnLine(snappedmappos);
                    if (float.IsInfinity(newscale) || float.IsNaN(newscale))
                    {
                        newscale = 99999f;
                    }
                    scale = (newscale * resizefilter) + scale * (1.0f - resizefilter);
                    if (float.IsInfinity(scale.x) || float.IsNaN(scale.x))
                    {
                        scale.x = 99999f;
                    }
                    if (float.IsInfinity(scale.y) || float.IsNaN(scale.y))
                    {
                        scale.y = 99999f;
                    }

                    // Show the extension line so that the user knows what it is aligning to
                    UpdateRectangleComponents();
                    Line2D edgeline;
                    if (resizefilter.x > resizefilter.y)
                    {
                        edgeline = new Line2D(corners[1], corners[2]);
                    }
                    else
                    {
                        edgeline = new Line2D(corners[3], corners[2]);
                    }
                    float nearestonedge = edgeline.GetNearestOnLine(snappedmappos);
                    if (nearestonedge > 0.5f)
                    {
                        extensionline = new Line2D(edgeline.v1, snappedmappos);
                    }
                    else
                    {
                        extensionline = new Line2D(edgeline.v2, snappedmappos);
                    }

                    break;

                case ModifyMode.Rotating:

                    // Snap to nearest vertex?
                    extensionline = new Line2D();
                    if (snaptonearest)
                    {
                        float vrange = BuilderPlug.Me.StitchRange / renderer.Scale;

                        // Try the nearest vertex
                        Vertex nv = MapSet.NearestVertexSquareRange(General.Map.Map.Vertices, snappedmappos, vrange);
                        if (nv != null)
                        {
                            snappedmappos = nv.Position;
                            dosnaptogrid  = false;

                            // Show the extension line so that the user knows what it is aligning to
                            extensionline = new Line2D(corners[0], snappedmappos);
                        }
                    }

                    Vector2D delta      = snappedmappos - rotationcenter;
                    float    deltaangle = -delta.GetAngle();

                    // Snap to grid?
                    if (dosnaptogrid)
                    {
                        // We make 8 vectors that the rotation can snap to
                        float founddistance = float.MaxValue;
                        float foundrotation = rotation;
                        for (int i = 0; i < 8; i++)
                        {
                            // Make the vectors
                            float    angle   = (float)i * Angle2D.PI * 0.25f;
                            Vector2D gridvec = Vector2D.FromAngle(angle);
                            Vector3D rotvec  = Vector2D.FromAngle(deltaangle + rotationoffset);

                            // Check distance
                            float dist = 2.0f - Vector2D.DotProduct(gridvec, rotvec);
                            if (dist < founddistance)
                            {
                                foundrotation = angle;
                                founddistance = dist;
                            }
                        }

                        // Keep rotation
                        rotation = foundrotation - sectorinfo[0].rotation;
                    }
                    else
                    {
                        rotation = deltaangle + rotationoffset - sectorinfo[0].rotation;
                    }
                    break;
                }

                UpdateSectors();
                General.Interface.RedrawDisplay();
            }
        }
        // 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);
            }
        }
Esempio n. 4
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;
        }
        /// <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);
            }
        }
Esempio n. 6
0
 public float GetNearestOnLine(LuaVector2D p)
 {
     return(l2d.GetNearestOnLine(p.vec));
 }
 public float GetNearestOnLine(Vector2 p)
 {
     return(Line2D.GetNearestOnLine(v1, v2, p));
 }
Esempio n. 8
0
    // This checks if a line is inside a triangle (touching the triangle is allowed)
    // NOTE: We already know p1 is on an edge segment of the triangle
    private static bool LineInsideTriangle(EarClipVertex[] t, Vector2D p1, Vector2D p2)
    {
        float s01             = Line2D.GetSideOfLine(t[0].Position, t[1].Position, p2);
        float s12             = Line2D.GetSideOfLine(t[1].Position, t[2].Position, p2);
        float s20             = Line2D.GetSideOfLine(t[2].Position, t[0].Position, p2);
        float p2_on_edge      = 2.0f;   // somewhere outside the 0 .. 1 range
        float p1_on_same_edge = 2.0f;

        // Test if p2 is inside the triangle
        if ((s01 < 0.0f) && (s12 < 0.0f) && (s20 < 0.0f))
        {
            // Line is inside triangle, because p2 is
            return(true);
        }

        // Test if p2 is on an edge of the triangle and if it is we would
        // like to know where on the edge segment p2 is
        if (s01 == 0.0f)
        {
            p2_on_edge      = Line2D.GetNearestOnLine(t[0].Position, t[1].Position, p2);
            p1_on_same_edge = Line2D.GetSideOfLine(t[0].Position, t[1].Position, p1);
        }
        else if (s12 == 0.0f)
        {
            p2_on_edge      = Line2D.GetNearestOnLine(t[1].Position, t[2].Position, p2);
            p1_on_same_edge = Line2D.GetSideOfLine(t[1].Position, t[2].Position, p1);
        }
        else if (s20 == 0.0f)
        {
            p2_on_edge      = Line2D.GetNearestOnLine(t[2].Position, t[0].Position, p2);
            p1_on_same_edge = Line2D.GetSideOfLine(t[2].Position, t[0].Position, p1);
        }

        // Is p2 actually on the edge segment?
        if ((p2_on_edge >= 0.0f) && (p2_on_edge <= 1.0f))
        {
            // If p1 is on the same edge (or the unlimited line of that edge)
            // then the line is not inside this triangle.
            if (p1_on_same_edge == 0.0f)
            {
                return(false);
            }
        }

        // Do a complete line-triangle intersection test
        // We already know p1 is not inside the triangle (possibly on an edge)
        Line2D p = new Line2D(p1, p2);
        Line2D t01 = new Line2D(t[0].Position, t[1].Position);
        Line2D t12 = new Line2D(t[1].Position, t[2].Position);
        Line2D t20 = new Line2D(t[2].Position, t[0].Position);
        float  pu, pt;

        //mxd. Test intersections
        if (t01.GetIntersection(p, out pu, out pt))
        {
            return(true);
        }
        if (t12.GetIntersection(p, out pu, out pt))
        {
            return(true);
        }
        if (t20.GetIntersection(p, out pu, out pt))
        {
            return(true);
        }

        return(false);
    }
Esempio n. 9
0
    // This checks if a given ear is a valid (no intersections from reflex vertices)
    private static bool CheckValidEar(EarClipVertex[] t, LinkedList <EarClipVertex> reflexes)
    {
        //mxd
        Vector2D pos0 = t[0].Position;
        Vector2D pos1 = t[1].Position;
        Vector2D pos2 = t[2].Position;
        Vector2D vpos;
        LinkedListNode <EarClipVertex> p;

        // Go for all reflex vertices
        foreach (EarClipVertex rv in reflexes)
        {
            // Not one of the triangle corners?
            if ((rv.Position != pos0) && (rv.Position != pos1) && (rv.Position != pos2))
            {
                // Return false on intersection

                // This checks if a point is inside a triangle
                // When the point is on an edge of the triangle, it depends on the lines
                // adjacent to the point if it is considered inside or not
                // NOTE: vertices in t must be in clockwise order!

                // If the triangle has no area, there can never be a point inside
                if (TriangleHasArea(t))
                {
                    //mxd
                    pos0 = t[0].Position;
                    pos1 = t[1].Position;
                    pos2 = t[2].Position;
                    p    = rv.MainListNode;
                    vpos = p.Value.Position;

                    //mxd. Check bounds first...
                    if (vpos.x < Math.Min(pos0.x, Math.Min(pos1.x, pos2.x)) ||
                        vpos.x > Math.Max(pos0.x, Math.Max(pos1.x, pos2.x)) ||
                        vpos.y < Math.Min(pos0.y, Math.Min(pos1.y, pos2.y)) ||
                        vpos.y > Math.Max(pos0.y, Math.Max(pos1.y, pos2.y)))
                    {
                        continue;
                    }

                    float lineside01 = Line2D.GetSideOfLine(pos0, pos1, vpos);
                    float lineside12 = Line2D.GetSideOfLine(pos1, pos2, vpos);
                    float lineside20 = Line2D.GetSideOfLine(pos2, pos0, vpos);
                    float u_on_line  = 0.5f;

                    // If point p is on the line of an edge, find out where on the edge segment p is.
                    if (lineside01 == 0.0f)
                    {
                        u_on_line = Line2D.GetNearestOnLine(pos0, pos1, vpos);
                    }
                    else if (lineside12 == 0.0f)
                    {
                        u_on_line = Line2D.GetNearestOnLine(pos1, pos2, vpos);
                    }
                    else if (lineside20 == 0.0f)
                    {
                        u_on_line = Line2D.GetNearestOnLine(pos2, pos0, vpos);
                    }

                    // If any of the lineside results are 0 then that means the point p lies on that edge and we
                    // need to test if the lines adjacent to the point p are in the triangle or not.
                    // If the lines are intersecting the triangle, we also consider the point inside.
                    if (lineside01 == 0.0f || lineside12 == 0.0f || lineside20 == 0.0f)
                    {
                        // When the point p is outside the edge segment, then it is not inside the triangle
                        if (u_on_line < 0.0f || u_on_line > 1.0f)
                        {
                            continue;
                        }

                        // Point p is on an edge segment. We'll have to decide by it's lines if we call it inside or outside the triangle.
                        LinkedListNode <EarClipVertex> p1 = p.Previous ?? p.List.Last;
                        if (LineInsideTriangle(t, vpos, p1.Value.Position))
                        {
                            return(false);
                        }

                        LinkedListNode <EarClipVertex> p2 = p.Next ?? p.List.First;
                        if (LineInsideTriangle(t, vpos, p2.Value.Position))
                        {
                            return(false);
                        }

                        continue;
                    }

                    if (lineside01 < 0.0f && lineside12 < 0.0f && lineside20 < 0.0f)
                    {
                        return(false);
                    }
                }
            }
        }

        // Valid ear!
        return(true);
    }
Esempio n. 10
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));
            }
        }
    }