protected override void Calculate <BaseSegment>(int index, BaseSegment segment) { var width = 1.0f; var height = 1.0f; segment.Height = height / (CountY); segment.Width = width / (CountX); SegmentPoint[] lastPoints = new SegmentPoint[4]; if (index != 0 && index % CountX != 0) { lastPoints = segments.FirstOrDefault(x => x.Index == index - 1).Points; } int Row = (int)(segment.Index / (CountX)); int Col = (int)(segment.Index / (CountY)); if (lastPoints[1] == null) { lastPoints[1] = new SegmentPoint(0, segment.Height * Row); } if (lastPoints[2] == null) { lastPoints[2] = new SegmentPoint(lastPoints[1].X, lastPoints[1].Y + segment.Height); } var startPoint2 = new SegmentPoint(lastPoints[1].X + segment.Width, lastPoints[1].Y); var startPoint3 = new SegmentPoint(lastPoints[2].X + segment.Width, lastPoints[2].Y); segment.Points = new SegmentPoint[4]; segment.Points[0] = (lastPoints[1]); segment.Points[1] = (startPoint2); segment.Points[2] = (startPoint3); segment.Points[3] = (lastPoints[2]); }
/// <summary> /// Default error function is evaluating how far we're from the last point /// given the current segment length. /// </summary> /// <param name="curve">Point curve.</param> /// <param name="curr">Current segment point.</param> /// <param name="next">Next segment point.</param> /// <param name="segmentType">Segment type.</param> /// <returns>0.0f unless segmentType == last, then distance from next to last point in list.</returns> public static float DefaultErrorFunc(PointCurve curve, SegmentPoint curr, SegmentPoint next, SegmentType segmentType) { if (segmentType == SegmentType.Last) { return(Mathf.Sign(1.0f - next.Time) * Vector3.Distance(next.Point, curve.Evaluate(1.0f).Point)); } return(0.0f); }
public SegmentLine(SegmentPoint A, SegmentPoint B, OverflowType LeftOverflowAction = OverflowType.AsLine, OverflowType RightOverflowAction = OverflowType.AsLine) { this.A = A; this.B = B; this.LOverflowAction = LeftOverflowAction; this.ROverflowAction = RightOverflowAction; InitParams(); }
public void CloneFrom(ref Segment segment) { Tl = segment.Tl; Tr = segment.Tr; Br = segment.Br; Bl = segment.Bl; Point = segment.Point; NextPoint = segment.NextPoint; HasFusedPoint = segment.HasFusedPoint; ShouldFuseBottom = segment.ShouldFuseBottom; Angle = segment.Angle; }
public void cloneFrom(ref Segment segment) { tl = segment.tl; tr = segment.tr; br = segment.br; bl = segment.bl; point = segment.point; nextPoint = segment.nextPoint; hasFusedPoint = segment.hasFusedPoint; shouldFuseBottom = segment.shouldFuseBottom; angle = segment.angle; }
public void setPoints(ref SegmentPoint point, ref SegmentPoint nextPoint) { angle = 0; this.point = point; this.nextPoint = nextPoint; // rotate 90 degrees before calculating and cache cos/sin var radians = Mathf.atan2(nextPoint.position.Y - point.position.Y, nextPoint.position.X - point.position.X); radians += MathHelper.PiOver2; var halfCos = Mathf.cos(radians) * 0.5f; var halfSin = Mathf.sin(radians) * 0.5f; tl = point.position - new Vector2(point.width * halfCos, point.width * halfSin); tr = nextPoint.position - new Vector2(nextPoint.width * halfCos, nextPoint.width * halfSin); br = nextPoint.position + new Vector2(nextPoint.width * halfCos, nextPoint.width * halfSin); bl = point.position + new Vector2(point.width * halfCos, point.width * halfSin); }
public void SetPoints(ref SegmentPoint point, ref SegmentPoint nextPoint) { Angle = 0; this.Point = point; this.NextPoint = nextPoint; // rotate 90 degrees before calculating and cache cos/sin var radians = Mathf.Atan2(nextPoint.Position.Y - point.Position.Y, nextPoint.Position.X - point.Position.X); radians += MathHelper.PiOver2; var halfCos = Mathf.Cos(radians) * 0.5f; var halfSin = Mathf.Sin(radians) * 0.5f; Tl = point.Position - new Vector2(point.Width * halfCos, point.Width * halfSin); Tr = nextPoint.Position - new Vector2(nextPoint.Width * halfCos, nextPoint.Width * halfSin); Br = nextPoint.Position + new Vector2(nextPoint.Width * halfCos, nextPoint.Width * halfSin); Bl = point.Position + new Vector2(point.Width * halfCos, point.Width * halfSin); }
protected void Calculate(int row, int col, BaseSegment segment) { segment.Height = CONSTS.COMPARING_MARKER_DIAMETER / CountY; segment.Width = CONSTS.COMPARING_MARKER_DIAMETER / CountX; SegmentPoint[] lastPoints = new SegmentPoint[4]; if (col != 0) { lastPoints = segments.FirstOrDefault(x => x.Index == segment.Index - 1).Points; } int Row = row; int Col = col; segment.Points = new SegmentPoint[4]; if (lastPoints == null || lastPoints[1] == null && lastPoints[2] == null) //nov red { segment.Points[0] = new SegmentPoint(CONSTS.COMPARING_MARKER_DIAMETER / 2 - (segment.Width / 2) * Row, segment.Height * Row); segment.Points[1] = segment.Points[0]; segment.Points[2] = new SegmentPoint(segment.Points[0].X + segment.Width / 2, segment.Points[0].Y + segment.Height); segment.Points[3] = new SegmentPoint(segment.Points[0].X - segment.Width / 2, segment.Points[0].Y + segment.Height); } else { if (Col % 2 == 0) //vseki 4eten element (pravilen) { segment.Points[0] = lastPoints[1]; //gore segment.Points[1] = segment.Points[0]; //gore segment.Points[2] = new SegmentPoint(lastPoints[2].X + segment.Width, lastPoints[2].Y); //dolu segment.Points[3] = lastPoints[2]; //dolu } else//(oburnat nadolu) { segment.Points[0] = lastPoints[0]; //gore segment.Points[1] = new SegmentPoint(lastPoints[0].X + segment.Width, lastPoints[0].Y); //gore segment.Points[2] = lastPoints[2]; //dolu segment.Points[3] = segment.Points[2]; //dolu } } }
protected override void Calculate <BaseSegment>(int index, BaseSegment segment) { SegmentPoint[] lastPoints = new SegmentPoint[4]; if (index != 0 && index % CountX != 0) { lastPoints = segments.FirstOrDefault(x => x.Index == index - 1).Points; } segment.Height = (CONSTS.COMPARING_MARKER_DIAMETER / 2f) / (CountY + 1); float AngleGrad = 360f / CountX; int Row = (int)(segment.Index / (CountX)); if (lastPoints[1] == null) { lastPoints[1] = new SegmentPoint(CONSTS.COMPARING_MARKER_DIAMETER / 2.0, CONSTS.COMPARING_MARKER_DIAMETER - segment.Height - segment.Height * Row); } if (lastPoints[2] == null) { lastPoints[2] = new SegmentPoint(CONSTS.COMPARING_MARKER_DIAMETER / 2.0, CONSTS.COMPARING_MARKER_DIAMETER - segment.Height * Row); } segment.Points = new SegmentPoint[4]; var startPoint2 = new SegmentPoint(0, 0); var startPoint3 = new SegmentPoint(0, 0); var startPoint1 = lastPoints[1]; var startPoint4 = lastPoints[2]; startPoint2.rotatePoint(startPoint1, new SegmentPoint(CONSTS.COMPARING_MARKER_DIAMETER / 2, CONSTS.COMPARING_MARKER_DIAMETER / 2), AngleGrad / (180 / Math.PI)); startPoint3.rotatePoint(startPoint4, new SegmentPoint(CONSTS.COMPARING_MARKER_DIAMETER / 2, CONSTS.COMPARING_MARKER_DIAMETER / 2), AngleGrad / (180 / Math.PI)); segment.Points[0] = (lastPoints[1]); segment.Points[1] = (startPoint2); segment.Points[2] = (startPoint3); segment.Points[3] = (lastPoints[2]); }
/// <summary> /// Evaluate curve at given time [0, 1]. /// </summary> /// <param name="t">Time along curve [0, 1].</param> /// <returns>Segment point at given time.</returns> public SegmentPoint Evaluate(float t) { if (m_points.Count < 2) { Debug.LogWarning("PointCurve.Evaluate called with an undefined curve #points < 2."); return(default(SegmentPoint)); } if (m_points.Count != m_time.Count && !Finalize()) { Debug.LogWarning("PointCurve.Finalize failed - length of curve is undefined: " + TotalLength); return(default(SegmentPoint)); } var index = FindIndex(t); if (index + 1 >= m_points.Count) { index = m_points.Count - 2; } var segment = new SegmentPoint(); segment.Begin = m_points[index]; segment.End = m_points[index + 1]; segment.Time = t; if (m_time[index] == m_time[index + 1]) { segment.LocalTime = 1.0f; segment.Point = segment.End; } else { segment.LocalTime = (t - m_time[index]) / (m_time[index + 1] - m_time[index]); segment.Point = segment.Begin + segment.LocalTime * (segment.End - segment.Begin); } return(segment); }
public static List <SegmentPath> segments_to_paths__sorted_list(List <Segment> segments, float distMax = 1e-10f) { List <SegmentPath> paths = new List <SegmentPath>(); //create a linked list of points sorted by x coordinate List <SegmentPoint> segmentPoints = new List <SegmentPoint>(); foreach (Segment s in segments) { SegmentPoint sp0 = new SegmentPoint(s.p[0], null); SegmentPoint sp1 = new SegmentPoint(s.p[1], sp0); sp0.otherSegmentPoint = sp1; segmentPoints.Add(sp0); segmentPoints.Add(sp1); } segmentPoints.Sort(); for (int i = 0; i < segmentPoints.Count - 1; i++) { segmentPoints[i].next = segmentPoints[i + 1]; } for (int i = 1; i < segmentPoints.Count; i++) { segmentPoints[i].prev = segmentPoints[i - 1]; } //process each segment foreach (SegmentPoint spMainLoop in segmentPoints) { //only process segments that are alive if (!spMainLoop.alive) { continue; } //start a new path with this segment spMainLoop.alive = false; spMainLoop.otherSegmentPoint.alive = false; SegmentPath path = new SegmentPath(spMainLoop.point, spMainLoop.otherSegmentPoint.point); paths.Add(path); //append/prepend points to path SegmentPoint spPath; //the current path point to append/prepend to SegmentPoint spTry; //the point that is examined to be appended/prepended bool found; //find points to APPEND to path spPath = spMainLoop.otherSegmentPoint; //APPEND (last point of path) do { found = false; //go FORWARD through the sorted list spTry = spPath.next; //FORWARD while (spTry != null && spTry.X - spPath.X <= distMax) //FORWARD try.x >= path.x { if (spTry.alive && Vector2F.DistanceManhattan(spPath.point, spTry.point) <= distMax) { spTry.alive = false; spTry.otherSegmentPoint.alive = false; spPath = spTry.otherSegmentPoint; path.p.AddLast(spPath.point); //APPEND found = true; break; } else { spTry = spTry.next; //FORWARD } } //if nothing found, then go BACKWARD through the sorted list if (!found) { spTry = spPath.prev; //BACKWARD while (spTry != null && spPath.X - spTry.X <= distMax) //BACKWARD path.x >= try.x { if (spTry.alive && Vector2F.DistanceManhattan(spPath.point, spTry.point) <= distMax) { spTry.alive = false; spTry.otherSegmentPoint.alive = false; spPath = spTry.otherSegmentPoint; path.p.AddLast(spPath.point); //APPEND found = true; break; } else { spTry = spTry.prev; //BACKWARD } } } } while (found); //find points to PREPEND to path spPath = spMainLoop; //PREPEND (first point of path) do { found = false; //go FORWARD through the sorted list spTry = spPath.next; //FORWARD while (spTry != null && spTry.X - spPath.X <= distMax) //FORWARD try.x >= path.x { if (spTry.alive && Vector2F.DistanceManhattan(spPath.point, spTry.point) <= distMax) { spTry.alive = false; spTry.otherSegmentPoint.alive = false; spPath = spTry.otherSegmentPoint; path.p.AddFirst(spPath.point); //PREPEND found = true; break; } else { spTry = spTry.next; //FORWARD } } //if nothing found, then go BACKWARD through the sorted list if (!found) { spTry = spPath.prev; //BACKWARD while (spTry != null && spPath.X - spTry.X <= distMax) //BACKWARD path.x >= try.x { if (spTry.alive && Vector2F.DistanceManhattan(spPath.point, spTry.point) <= distMax) { spTry.alive = false; spTry.otherSegmentPoint.alive = false; spPath = spTry.otherSegmentPoint; path.p.AddFirst(spPath.point); //PREPEND found = true; break; } else { spTry = spTry.prev; //BACKWARD } } } } while (found); } return(paths); }
void calculateVertices() { if (!_areVertsDirty || _points.length < 2) { return; } _areVertsDirty = false; _indices.reset(); _vertices.reset(); var maxX = float.MinValue; var minX = float.MaxValue; var maxY = float.MinValue; var minY = float.MaxValue; if (_useStartEndWidths) { _maxWidth = System.Math.Max(_startWidth, _endWidth); } // calculate line length first and simulataneously get our min/max points for the bounds var lineLength = 0f; var halfMaxWidth = _maxWidth * 0.5f; _points.buffer[0].lengthFromPreviousPoint = 0; for (var i = 0; i < _points.length - 1; i++) { var distance = Vector2.Distance(_points.buffer[i].position, _points.buffer[i + 1].position); _points.buffer[i + 1].lengthFromPreviousPoint = distance; lineLength += distance; maxX = Mathf.maxOf(maxX, _points.buffer[i].position.X + halfMaxWidth, _points.buffer[i + 1].position.X + halfMaxWidth); minX = Mathf.minOf(minX, _points.buffer[i].position.X - halfMaxWidth, _points.buffer[i + 1].position.X - halfMaxWidth); maxY = Mathf.maxOf(maxY, _points.buffer[i].position.Y + halfMaxWidth, _points.buffer[i + 1].position.Y + halfMaxWidth); minY = Mathf.minOf(minY, _points.buffer[i].position.Y - halfMaxWidth, _points.buffer[i + 1].position.Y - halfMaxWidth); } _bounds.x = minX; _bounds.y = minY; _bounds.width = maxX - minX; _bounds.height = maxY - minY; // special case: single segment if (_points.length == 2) { if (_useStartEndWidths) { _points.buffer[0].width = _startWidth; _points.buffer[1].width = _endWidth; } if (_useStartEndColors) { _points.buffer[0].color = _startColor; _points.buffer[1].color = _endColor; } _firstSegment.setPoints(ref _points.buffer[0], ref _points.buffer[1]); addSingleSegmentLine(ref _firstSegment, _points.buffer[1].color); return; } var distanceSoFar = 0f; var fusedPoint = Vector2.Zero; var vertIndex = 0; var thirdPoint = new SegmentPoint(); for (var i = 0; i < _points.length - 1; i++) { var firstPoint = _points.buffer[i]; var secondPoint = _points.buffer[i + 1]; var hasThirdPoint = _points.length > i + 2; if (hasThirdPoint) { thirdPoint = _points.buffer[i + 2]; } // we need the distance along the line of both the first and second points. distanceSoFar will always be for the furthest point // which is the previous point before adding the current segment distance. var firstPointDistance = distanceSoFar; distanceSoFar += secondPoint.lengthFromPreviousPoint; var firstPointRatio = firstPointDistance / lineLength; var secondPointRatio = distanceSoFar / lineLength; var thirdPointRatio = 0f; if (hasThirdPoint) { thirdPointRatio = (distanceSoFar + thirdPoint.lengthFromPreviousPoint) / lineLength; } if (_useStartEndColors) { ColorExt.lerp(ref _startColor, ref _endColor, out firstPoint.color, firstPointRatio); ColorExt.lerp(ref _startColor, ref _endColor, out secondPoint.color, secondPointRatio); if (hasThirdPoint) { ColorExt.lerp(ref _startColor, ref _endColor, out thirdPoint.color, thirdPointRatio); } } if (_useStartEndWidths) { firstPoint.width = Mathf.lerp(_startWidth, _endWidth, firstPointRatio); secondPoint.width = Mathf.lerp(_startWidth, _endWidth, secondPointRatio); if (hasThirdPoint) { thirdPoint.width = Mathf.lerp(_startWidth, _endWidth, thirdPointRatio); } } if (i == 0) { _firstSegment.setPoints(ref firstPoint, ref secondPoint); _secondSegment.setPoints(ref secondPoint, ref thirdPoint); } else { Utils.swap(ref _firstSegment, ref _secondSegment); if (hasThirdPoint) { _secondSegment.setPoints(ref secondPoint, ref thirdPoint); } } // dont recalculate the fusedPoint for the last segment since there will be no third point to work with if (hasThirdPoint) { var shouldFuseBottom = Vector2Ext.isTriangleCCW(firstPoint.position, secondPoint.position, thirdPoint.position); _secondSegment.setFusedData(shouldFuseBottom, ref _firstSegment); } // special care needs to be take with the first segment since it has a different vert count if (i == 0) { addFirstSegment(ref _firstSegment, ref _secondSegment, ref vertIndex); } else { addSegment(ref _firstSegment, ref vertIndex); } _lastSegment.cloneFrom(ref _firstSegment); } }
void calculateVertices() { if( !_areVertsDirty || _points.length < 2 ) return; _areVertsDirty = false; _indices.reset(); _vertices.reset(); var maxX = float.MinValue; var minX = float.MaxValue; var maxY = float.MinValue; var minY = float.MaxValue; if( _useStartEndWidths ) _maxWidth = System.Math.Max( _startWidth, _endWidth ); // calculate line length first and simulataneously get our min/max points for the bounds var lineLength = 0f; var halfMaxWidth = _maxWidth * 0.5f; _points.buffer[0].lengthFromPreviousPoint = 0; for( var i = 0; i < _points.length - 1; i++ ) { var distance = Vector2.Distance( _points.buffer[i].position, _points.buffer[i + 1].position ); _points.buffer[i + 1].lengthFromPreviousPoint = distance; lineLength += distance; maxX = Mathf.maxOf( maxX, _points.buffer[i].position.X + halfMaxWidth, _points.buffer[i + 1].position.X + halfMaxWidth ); minX = Mathf.minOf( minX, _points.buffer[i].position.X - halfMaxWidth, _points.buffer[i + 1].position.X - halfMaxWidth ); maxY = Mathf.maxOf( maxY, _points.buffer[i].position.Y + halfMaxWidth, _points.buffer[i + 1].position.Y + halfMaxWidth ); minY = Mathf.minOf( minY, _points.buffer[i].position.Y - halfMaxWidth, _points.buffer[i + 1].position.Y - halfMaxWidth ); } _bounds.x = minX; _bounds.y = minY; _bounds.width = maxX - minX; _bounds.height = maxY - minY; // special case: single segment if( _points.length == 2 ) { if( _useStartEndWidths ) { _points.buffer[0].width = _startWidth; _points.buffer[1].width = _endWidth; } if( _useStartEndColors ) { _points.buffer[0].color = _startColor; _points.buffer[1].color = _endColor; } _firstSegment.setPoints( ref _points.buffer[0], ref _points.buffer[1] ); addSingleSegmentLine( ref _firstSegment, _points.buffer[1].color); return; } var distanceSoFar = 0f; var fusedPoint = Vector2.Zero; var vertIndex = 0; var thirdPoint = new SegmentPoint(); for( var i = 0; i < _points.length - 1; i++ ) { var firstPoint = _points.buffer[i]; var secondPoint = _points.buffer[i + 1]; var hasThirdPoint = _points.length > i + 2; if( hasThirdPoint ) thirdPoint = _points.buffer[i + 2]; // we need the distance along the line of both the first and second points. distanceSoFar will always be for the furthest point // which is the previous point before adding the current segment distance. var firstPointDistance = distanceSoFar; distanceSoFar += secondPoint.lengthFromPreviousPoint; var firstPointRatio = firstPointDistance / lineLength; var secondPointRatio = distanceSoFar / lineLength; var thirdPointRatio = 0f; if( hasThirdPoint ) thirdPointRatio = ( distanceSoFar + thirdPoint.lengthFromPreviousPoint ) / lineLength; if( _useStartEndColors ) { ColorExt.lerp( ref _startColor, ref _endColor, out firstPoint.color, firstPointRatio ); ColorExt.lerp( ref _startColor, ref _endColor, out secondPoint.color, secondPointRatio ); if( hasThirdPoint ) ColorExt.lerp( ref _startColor, ref _endColor, out thirdPoint.color, thirdPointRatio ); } if( _useStartEndWidths ) { firstPoint.width = Mathf.lerp( _startWidth, _endWidth, firstPointRatio ); secondPoint.width = Mathf.lerp( _startWidth, _endWidth, secondPointRatio ); if( hasThirdPoint ) thirdPoint.width = Mathf.lerp( _startWidth, _endWidth, thirdPointRatio ); } if( i == 0 ) { _firstSegment.setPoints( ref firstPoint, ref secondPoint ); _secondSegment.setPoints( ref secondPoint, ref thirdPoint ); } else { Utils.swap( ref _firstSegment, ref _secondSegment ); if( hasThirdPoint ) _secondSegment.setPoints( ref secondPoint, ref thirdPoint ); } // dont recalculate the fusedPoint for the last segment since there will be no third point to work with if( hasThirdPoint ) { var shouldFuseBottom = Vector2Ext.isTriangleCCW( firstPoint.position, secondPoint.position, thirdPoint.position ); _secondSegment.setFusedData( shouldFuseBottom, ref _firstSegment ); } // special care needs to be take with the first segment since it has a different vert count if( i == 0 ) addFirstSegment( ref _firstSegment, ref _secondSegment, ref vertIndex ); else addSegment( ref _firstSegment, ref vertIndex ); _lastSegment.cloneFrom( ref _firstSegment ); } }
public void setPoints( ref SegmentPoint point, ref SegmentPoint nextPoint ) { angle = 0; this.point = point; this.nextPoint = nextPoint; // rotate 90 degrees before calculating and cache cos/sin var radians = Mathf.atan2( nextPoint.position.Y - point.position.Y, nextPoint.position.X - point.position.X ); radians += MathHelper.PiOver2; var halfCos = Mathf.cos( radians ) * 0.5f; var halfSin = Mathf.sin( radians ) * 0.5f; tl = point.position - new Vector2( point.width * halfCos, point.width * halfSin ); tr = nextPoint.position - new Vector2( nextPoint.width * halfCos, nextPoint.width * halfSin ); br = nextPoint.position + new Vector2( nextPoint.width * halfCos, nextPoint.width * halfSin ); bl = point.position + new Vector2( point.width * halfCos, point.width * halfSin ); }
public void cloneFrom( ref Segment segment ) { tl = segment.tl; tr = segment.tr; br = segment.br; bl = segment.bl; point = segment.point; nextPoint = segment.nextPoint; hasFusedPoint = segment.hasFusedPoint; shouldFuseBottom = segment.shouldFuseBottom; angle = segment.angle; }
private static List <Segment> RemoveIntersections(List <Segment> segments, int coord, Segment.Type type) { List <SegmentPoint> points = new List <SegmentPoint>(); List <Segment> outSegments = new List <Segment>(); foreach (var segment in segments) { if (Segment.Horizontal(type)) { points.Add(new SegmentPoint(segment.Start.X, segment.SegmentType, SegmentPoint.PointType.Start)); points.Add(new SegmentPoint(segment.End.X, segment.SegmentType, SegmentPoint.PointType.End)); } else { points.Add(new SegmentPoint(segment.Start.Y, segment.SegmentType, SegmentPoint.PointType.Start)); points.Add(new SegmentPoint(segment.End.Y, segment.SegmentType, SegmentPoint.PointType.End)); } } Segment.Type currentType = points[0].SegmentType; var currentPoint = points[0]; var startFound = true; bool isIntersection = false; bool isFirst = true; int lastAdded = int.MinValue; var sortedPoints = points.OrderBy(x => x.Coordinates).ToList(); for (int i = 0; i < sortedPoints.Count - 1; i++) { if (sortedPoints[i].Coordinates == sortedPoints[i + 1].Coordinates && sortedPoints[i].SegmentType == sortedPoints[i + 1].SegmentType) { sortedPoints[i].Type = SegmentPoint.PointType.Start; sortedPoints[i + 1].Type = SegmentPoint.PointType.Start; /*удаление из середины листа слишком долгая операция, сделаем точку стартовой * и она не будет рассматриваться в автомате */ } } foreach (var point in sortedPoints) { if (isFirst) { currentType = point.SegmentType; currentPoint = point; startFound = true; isFirst = false; continue; } if (isIntersection) { startFound = true; currentPoint = point; currentType = Segment.OppositeType(point.SegmentType); isIntersection = false; continue; } if (!startFound && point.Type == SegmentPoint.PointType.Start) { if (lastAdded == point.Coordinates && outSegments.Last().SegmentType == point.SegmentType) { var lastSegment = outSegments.Last(); outSegments.RemoveAt(outSegments.Count - 1); startFound = true; if (Segment.Horizontal(type)) { currentPoint = new SegmentPoint(lastSegment.Start.X, point.SegmentType, SegmentPoint.PointType.Start); } else { currentPoint = new SegmentPoint(lastSegment.Start.Y, point.SegmentType, SegmentPoint.PointType.Start); } continue; } currentPoint = point; startFound = true; currentType = point.SegmentType; continue; } if (startFound && point.SegmentType == currentType && point.Type == SegmentPoint.PointType.End) { if (Segment.Horizontal(type)) { outSegments.Add(new Segment(currentPoint.Coordinates, coord, point.Coordinates, coord, currentType)); } else { outSegments.Add(new Segment(coord, currentPoint.Coordinates, coord, point.Coordinates, currentType)); } lastAdded = point.Coordinates; startFound = false; continue; } if (startFound && point.SegmentType != currentType) { if (Segment.Horizontal(type)) { outSegments.Add(new Segment(currentPoint.Coordinates, coord, point.Coordinates, coord, currentType)); } else { outSegments.Add(new Segment(coord, currentPoint.Coordinates, coord, point.Coordinates, currentType)); } lastAdded = point.Coordinates; startFound = false; isIntersection = true; continue; } } return(outSegments.Where(x => x.Length > 0).ToList()); }
// instance functions /// <summary>Takes an offset relative to the beginning of this track segment and returns the point on the track corresponding to this offset in an output parameter.</summary> /// <param name="offset">The offset relative to the beginning of this track segment. A value of zero corresponds to the beginning of this track segment, while a value of the underlying Length field corresponds to the end of this track segment.</param> /// <param name="point">Receives point on the track, including its position, orientation and roll.</param> /// <returns>The success of the operation. This operation fails if the specified offset points to a point outside of the available track.</returns> public bool GetPoint(double offset, out SegmentPoint point) { if (offset < 0.0) { /* * The offset is negative and thus outside the bounds of this segment. * We need to continue processing with the previous segment. * */ if (this.Previous.Segment is PhysicalSegment) { PhysicalSegment previous = (PhysicalSegment)this.Previous.Segment; SegmentEndpoint endpoint = this.Previous.Endpoint; if (endpoint == SegmentEndpoint.Beginning) { return GetPoint(-offset, out point); } else if (endpoint == SegmentEndpoint.End) { return GetPoint(previous.Length + offset, out point); } else { throw new InvalidOperationException(); } } else if (this.Previous.Segment is VirtualSegment) { // TODO: Virtual segments can have various endpoints. // Each virtual segment needs to be handled specially. throw new NotImplementedException(); } else if (this.Previous.Segment == null) { point = SegmentPoint.Invalid; return false; } else { throw new InvalidOperationException(); } } else if (offset > this.Length) { /* * The offset exceeds the length of this segment and is thus outside the bounds of this segment. * We need to continue processing with the next segment. * */ if (this.Next.Segment is PhysicalSegment) { PhysicalSegment next = (PhysicalSegment)this.Next.Segment; SegmentEndpoint endpoint = this.Next.Endpoint; if (endpoint == SegmentEndpoint.Beginning) { return GetPoint(offset - this.Length, out point); } else if (endpoint == SegmentEndpoint.End) { return GetPoint(this.Length + next.Length - offset, out point); } else { throw new InvalidOperationException(); } } else if (this.Next.Segment is VirtualSegment) { // TODO: Virtual segments can have various endpoints. // Each virtual segment needs to be handled specially. throw new NotImplementedException(); } else if (this.Next.Segment == null) { point = SegmentPoint.Invalid; return false; } else { throw new InvalidOperationException(); } } else { /* * The offset is within the bounds of this segment. * We can calculate the track point data now. * */ if (this is StraightSegment) { StraightSegment straight = (StraightSegment)this; Math.Vector3 position = straight.Position + offset * straight.Orientation.Z; double rollFactor = offset / straight.Length; double roll = (1.0 - rollFactor) * straight.StartingRoll + rollFactor * straight.EndingRoll; point = new SegmentPoint(this, position, straight.Orientation, false, roll); return true; } else if (this is CurvedSegment) { CurvedSegment curve = (CurvedSegment)this; double angle = offset / curve.Radius; double cosineOfAngle = System.Math.Cos(angle); double sineOfAngle = System.Math.Sin(angle); double radiusX = curve.Radius * cosineOfAngle; double radiusZ = curve.Radius * sineOfAngle; Math.Vector3 position = curve.Center - radiusX * curve.Orientation.X + radiusZ * curve.Orientation.Z; Math.Orientation3 orientation = Math.Orientation3.RotateAroundYAxis(curve.Orientation, cosineOfAngle, sineOfAngle); double rollFactor = offset / curve.Length; double roll = (1.0 - rollFactor) * curve.StartingRoll + rollFactor * curve.EndingRoll; point = new SegmentPoint(this, position, orientation, false, roll); return true; } else { throw new InvalidOperationException(); } } }