protected virtual void UpdateRenderPoints()
        {
            ComputeControlPoints(); // This should have been updated before : make sure anyway.

            if (m_RenderPointsDirty == false && m_ControlPoints != null)
            {
                return;
            }

            m_RenderPointsDirty = false;
            m_MeshDirty         = true;

            m_RenderPoints.Clear();

            float diameter = k_EdgeTurnDiameter;

            Vector2 p1 = parent.ChangeCoordinatesTo(this, m_ControlPoints[0]);
            Vector2 p2 = parent.ChangeCoordinatesTo(this, m_ControlPoints[1]);
            Vector2 p3 = parent.ChangeCoordinatesTo(this, m_ControlPoints[2]);
            Vector2 p4 = parent.ChangeCoordinatesTo(this, m_ControlPoints[3]);

            // We have to handle a special case of the edge when it is a straight line, but not
            // when going backwards in space (where the start point is in front in y to the end point).
            // We do this by turning the line into 3 linear segments with no curves. This also
            // avoids possible NANs in later angle calculations.
            if ((orientation == Orientation.Horizontal && Mathf.Abs(p1.y - p4.y) < 2 && p1.x + k_EdgeLengthFromPort < p4.x - k_EdgeLengthFromPort) ||
                (orientation == Orientation.Vertical && Mathf.Abs(p1.x - p4.x) < 2 && p1.y + k_EdgeLengthFromPort < p4.y - k_EdgeLengthFromPort))
            {
                RenderStraightLines(p1, p2, p3, p4);

                return;
            }


            EdgeCornerSweepValues corner1 = GetCornerSweepValues(p1, p2, p3, diameter, Direction.Output);
            EdgeCornerSweepValues corner2 = GetCornerSweepValues(p2, p3, p4, diameter, Direction.Input);

            if (!ValidateCornerSweepValues(ref corner1, ref corner2))
            {
                RenderStraightLines(p1, p2, p3, p4);

                return;
            }

            m_RenderPoints.Add(p1);

            GetRoundedCornerPoints(m_RenderPoints, corner1, Direction.Output);
            GetRoundedCornerPoints(m_RenderPoints, corner2, Direction.Input);

            m_RenderPoints.Add(p4);
        }
Example #2
0
        private void GetRoundedCornerPoints(List <Vector2> points, EdgeCornerSweepValues corner, Direction closestPortDirection)
        {
            // Calculate the number of points that will sample the arc from the sweep angle.
            int  pointsCount = Mathf.CeilToInt((float)Math.Abs(corner.sweepAngle * k_EdgeSweepResampleRatio));
            int  sign        = Math.Sign(corner.sweepAngle);
            bool backwards   = (closestPortDirection == Direction.Input);

            for (int i = 0; i < pointsCount; ++i)
            {
                // If we are computing the second corner (into the input port), the sweep is going backwards
                // but we still need to add the points to the list in the correct order.
                float sweepIndex = backwards ? i - pointsCount : i;

                double sweepedAngle = corner.startAngle + sign * sweepIndex / k_EdgeSweepResampleRatio;

                var pointX = (float)(corner.circleCenter.x + Math.Cos(sweepedAngle) * corner.radius);
                var pointY = (float)(corner.circleCenter.y + Math.Sin(sweepedAngle) * corner.radius);

                // Check if we overlap the previous point. If we do, we skip this point so that we
                // don't cause the edge polygons to twist.
                if (i == 0 && backwards)
                {
                    if (outputOrientation == Orientation.Horizontal)
                    {
                        if (corner.sweepAngle < 0 && points[points.Count - 1].y > pointY)
                        {
                            continue;
                        }
                        else if (corner.sweepAngle >= 0 && points[points.Count - 1].y < pointY)
                        {
                            continue;
                        }
                    }
                    else
                    {
                        if (corner.sweepAngle < 0 && points[points.Count - 1].x < pointX)
                        {
                            continue;
                        }
                        else if (corner.sweepAngle >= 0 && points[points.Count - 1].x > pointX)
                        {
                            continue;
                        }
                    }
                }

                points.Add(new Vector2(pointX, pointY));
            }
        }
Example #3
0
        private bool ValidateCornerSweepValues(ref EdgeCornerSweepValues corner1, ref EdgeCornerSweepValues corner2)
        {
            // Get the midpoint between the two corner circle centers.
            Vector2 circlesMidpoint = (corner1.circleCenter + corner2.circleCenter) / 2;

            // Find the angle to the corner circles midpoint so we can compare it to the sweep angles of each corner.
            Vector2 p2CenterToCross1     = corner1.circleCenter - corner1.crossPoint1;
            Vector2 p2CenterToCirclesMid = corner1.circleCenter - circlesMidpoint;
            double  angleToCirclesMid    = outputOrientation == Orientation.Horizontal
                ? Math.Atan2(p2CenterToCross1.y, p2CenterToCross1.x) - Math.Atan2(p2CenterToCirclesMid.y, p2CenterToCirclesMid.x)
                : Math.Atan2(p2CenterToCross1.x, p2CenterToCross1.y) - Math.Atan2(p2CenterToCirclesMid.x, p2CenterToCirclesMid.y);

            if (double.IsNaN(angleToCirclesMid))
            {
                return(false);
            }

            // We need the angle to the circles midpoint to match the turn direction of the first corner's sweep angle.
            angleToCirclesMid = Math.Sign(angleToCirclesMid) * 2 * Mathf.PI - angleToCirclesMid;
            if (Mathf.Abs((float)angleToCirclesMid) > 1.5 * Mathf.PI)
            {
                angleToCirclesMid = -1 * Math.Sign(angleToCirclesMid) * 2 * Mathf.PI + angleToCirclesMid;
            }

            // Calculate the maximum sweep angle so that both corner sweeps and with the tangents of the 2 circles meeting each other.
            float h = p2CenterToCirclesMid.magnitude;
            float p2AngleToMidTangent = Mathf.Acos(corner1.radius / h);

            if (double.IsNaN(p2AngleToMidTangent))
            {
                return(false);
            }

            float maxSweepAngle = Mathf.Abs((float)corner1.sweepAngle) - p2AngleToMidTangent * 2;

            // If the angle to the circles midpoint is within the sweep angle, we need to apply our maximum sweep angle
            // calculated above, otherwise the maximum sweep angle is irrelevant.
            if (Mathf.Abs((float)angleToCirclesMid) < Mathf.Abs((float)corner1.sweepAngle))
            {
                corner1.sweepAngle = Math.Sign(corner1.sweepAngle) * Mathf.Min(maxSweepAngle, Mathf.Abs((float)corner1.sweepAngle));
                corner2.sweepAngle = Math.Sign(corner2.sweepAngle) * Mathf.Min(maxSweepAngle, Mathf.Abs((float)corner2.sweepAngle));
            }

            return(true);
        }
Example #4
0
        private EdgeCornerSweepValues GetCornerSweepValues(
            Vector2 p1, Vector2 cornerPoint, Vector2 p2, float diameter, Direction closestPortDirection)
        {
            EdgeCornerSweepValues corner = new EdgeCornerSweepValues();

            // Calculate initial radius. This radius can change depending on the sharpness of the corner.
            corner.radius = diameter / 2;

            // Calculate vectors from p1 to cornerPoint.
            Vector2 d1Corner = (cornerPoint - p1).normalized;
            Vector2 d1       = d1Corner * diameter;
            float   dx1      = d1.x;
            float   dy1      = d1.y;

            // Calculate vectors from p2 to cornerPoint.
            Vector2 d2Corner = (cornerPoint - p2).normalized;
            Vector2 d2       = d2Corner * diameter;
            float   dx2      = d2.x;
            float   dy2      = d2.y;

            // Calculate the angle of the corner (divided by 2).
            float angle = (float)(Math.Atan2(dy1, dx1) - Math.Atan2(dy2, dx2)) / 2;

            // Calculate the length of the segment between the cornerPoint and where
            // the corner circle with given radius meets the line.
            float tan     = (float)Math.Abs(Math.Tan(angle));
            float segment = corner.radius / tan;

            // If the segment is larger than the diameter, we need to cap the segment
            // to the diameter and reduce the radius to match the segment. This is what
            // makes the corner turn radii get smaller as the edge corners get tighter.
            if (segment > diameter)
            {
                segment       = diameter;
                corner.radius = diameter * tan;
            }

            // Calculate both cross points (where the circle touches the p1-cornerPoint line
            // and the p2-cornerPoint line).
            corner.crossPoint1 = cornerPoint - (d1Corner * segment);
            corner.crossPoint2 = cornerPoint - (d2Corner * segment);

            // Calculation of the coordinates of the circle center.
            corner.circleCenter = GetCornerCircleCenter(cornerPoint, corner.crossPoint1, corner.crossPoint2, segment, corner.radius);

            // Calculate the starting and ending angles.
            corner.startAngle = Math.Atan2(corner.crossPoint1.y - corner.circleCenter.y, corner.crossPoint1.x - corner.circleCenter.x);
            corner.endAngle   = Math.Atan2(corner.crossPoint2.y - corner.circleCenter.y, corner.crossPoint2.x - corner.circleCenter.x);

            // Get the full sweep angle from the starting and ending angles.
            corner.sweepAngle = corner.endAngle - corner.startAngle;

            // If we are computing the second corner (into the input port), we want to start
            // the sweep going backwards.
            if (closestPortDirection == Direction.Input)
            {
                double endAngle = corner.endAngle;
                corner.endAngle   = corner.startAngle;
                corner.startAngle = endAngle;
            }

            // Validate the sweep angle so it turns into the correct direction.
            if (corner.sweepAngle > Math.PI)
            {
                corner.sweepAngle = -2 * Math.PI + corner.sweepAngle;
            }
            else if (corner.sweepAngle < -Math.PI)
            {
                corner.sweepAngle = 2 * Math.PI + corner.sweepAngle;
            }

            return(corner);
        }
Example #5
0
        protected virtual void UpdateRenderPoints()
        {
            ComputeControlPoints(); // This should have been updated before : make sure anyway.

            if (m_RenderPointsDirty == false && m_ControlPoints != null)
            {
                return;
            }

            Vector2 p1 = parent.ChangeCoordinatesTo(this, m_ControlPoints[0]);
            Vector2 p2 = parent.ChangeCoordinatesTo(this, m_ControlPoints[1]);
            Vector2 p3 = parent.ChangeCoordinatesTo(this, m_ControlPoints[2]);
            Vector2 p4 = parent.ChangeCoordinatesTo(this, m_ControlPoints[3]);

            // Only compute this when the "local" points have actually changed
            if (lastLocalControlPoints.Count == 4)
            {
                if (Approximately(p1, lastLocalControlPoints[0]) &&
                    Approximately(p2, lastLocalControlPoints[1]) &&
                    Approximately(p3, lastLocalControlPoints[2]) &&
                    Approximately(p4, lastLocalControlPoints[3]))
                {
                    m_RenderPointsDirty = false;
                    return;
                }
            }

            Profiler.BeginSample("EdgeControl.UpdateRenderPoints");
            lastLocalControlPoints.Clear();
            lastLocalControlPoints.Add(p1);
            lastLocalControlPoints.Add(p2);
            lastLocalControlPoints.Add(p3);
            lastLocalControlPoints.Add(p4);
            m_RenderPointsDirty = false;

            m_RenderPoints.Clear();

            float diameter = k_EdgeTurnDiameter;

            // We have to handle a special case of the edge when it is a straight line, but not
            // when going backwards in space (where the start point is in front in y to the end point).
            // We do this by turning the line into 3 linear segments with no curves. This also
            // avoids possible NANs in later angle calculations.
            bool sameOrientations = outputOrientation == inputOrientation;

            if (sameOrientations &&
                ((outputOrientation == Orientation.Horizontal && Mathf.Abs(p1.y - p4.y) < 2 && p1.x + k_EdgeLengthFromPort < p4.x - k_EdgeLengthFromPort) ||
                 (outputOrientation == Orientation.Vertical && Mathf.Abs(p1.x - p4.x) < 2 && p1.y + k_EdgeLengthFromPort < p4.y - k_EdgeLengthFromPort)))
            {
                RenderStraightLines(p1, p2, p3, p4);
                Profiler.EndSample();
                return;
            }

            bool renderBothCorners = true;

            EdgeCornerSweepValues corner1 = GetCornerSweepValues(p1, p2, p3, diameter, Direction.Output);
            EdgeCornerSweepValues corner2 = GetCornerSweepValues(p2, p3, p4, diameter, Direction.Input);

            if (!ValidateCornerSweepValues(ref corner1, ref corner2))
            {
                if (sameOrientations)
                {
                    RenderStraightLines(p1, p2, p3, p4);
                    Profiler.EndSample();
                    return;
                }

                renderBothCorners = false;

                //we try to do it with a single corner instead
                Vector2 px = (outputOrientation == Orientation.Horizontal) ? new Vector2(p4.x, p1.y) : new Vector2(p1.x, p4.y);

                corner1 = GetCornerSweepValues(p1, px, p4, diameter, Direction.Output);
            }

            m_RenderPoints.Add(p1);

            if (!sameOrientations && renderBothCorners)
            {
                //if the 2 corners or endpoints are too close, the corner sweep angle calculations can't handle different orientations
                float minDistance = 2 * diameter * diameter;
                if ((p3 - p2).sqrMagnitude < minDistance ||
                    (p4 - p1).sqrMagnitude < minDistance)
                {
                    Vector2 px = (p2 + p3) * 0.5f;
                    corner1           = GetCornerSweepValues(p1, px, p4, diameter, Direction.Output);
                    renderBothCorners = false;
                }
            }

            GetRoundedCornerPoints(m_RenderPoints, corner1, Direction.Output);
            if (renderBothCorners)
            {
                GetRoundedCornerPoints(m_RenderPoints, corner2, Direction.Input);
            }

            m_RenderPoints.Add(p4);
            Profiler.EndSample();
        }