/// <summary> /// Add points for a circular fillet around a reflex corner. /// Adds the start and end points /// </summary> /// <param name="p">Base point of curve</param> /// <param name="p0">Start point of fillet curve</param> /// <param name="p1">Endpoint of fillet curve</param> /// <param name="direction">The orientation of the fillet</param> /// <param name="radius">The radius of the fillet</param> private void AddCornerFillet(Coordinate p, Coordinate p0, Coordinate p1, OrientationIndex direction, double radius) { double dx0 = p0.X - p.X; double dy0 = p0.Y - p.Y; double startAngle = Math.Atan2(dy0, dx0); double dx1 = p1.X - p.X; double dy1 = p1.Y - p.Y; double endAngle = Math.Atan2(dy1, dx1); if (direction == OrientationIndex.Clockwise) { if (startAngle <= endAngle) { startAngle += 2.0 * Math.PI; } } else { // direction == COUNTERCLOCKWISE if (startAngle >= endAngle) { startAngle -= 2.0 * Math.PI; } } _segList.AddPt(p0); AddDirectedFillet(p, startAngle, endAngle, direction, radius); _segList.AddPt(p1); }
/// <summary> /// Adds the offset points for an outside (convex) turn /// </summary> private void AddOutsideTurn(OrientationIndex orientation, bool addStartPoint) { /** * Heuristic: If offset endpoints are very close together, * just use one of them as the corner vertex. * This avoids problems with computing mitre corners in the case * where the two segments are almost parallel * (which is hard to compute a robust intersection for). */ if (_offset0.P1.Distance(_offset1.P0) < _distance * OffsetSegmentSeparationFactor) { _segList.AddPt(_offset0.P1); return; } if (_bufParams.JoinStyle == JoinStyle.Mitre) { AddMitreJoin(_s1, _offset0, _offset1, _distance); } else if (_bufParams.JoinStyle == JoinStyle.Bevel) { AddBevelJoin(_offset0, _offset1); } else { // add a circular fillet connecting the endpoints of the offset segments if (addStartPoint) { _segList.AddPt(_offset0.P1); } // TESTING - comment out to produce beveled joins AddCornerFillet(_s1, _offset0.P1, _offset1.P0, orientation, _distance); _segList.AddPt(_offset1.P0); } }
///<summary> /// Adds points for a circular fillet arc between two specified angles. ///</summary> ///<remarks> /// The start and end point for the fillet are not added - the caller must add them if required. ///</remarks> /// <param name="p">The point around which to add the fillet points</param> /// <param name="startAngle">The start angle (in radians)</param> /// <param name="endAngle">The end angle (in radians)</param> /// <param name="direction">Is -1 for a CW angle, 1 for a CCW angle</param> /// <param name="radius">The radius of the fillet</param> private void AddFillet(Coordinate p, double startAngle, double endAngle, OrientationIndex direction, double radius) { int directionFactor = direction == OrientationIndex.Clockwise ? -1 : 1; double totalAngle = Math.Abs(startAngle - endAngle); int nSegs = (int)(totalAngle / _filletAngleQuantum + 0.5); if (nSegs < 1) { return; // no segments because angle is less than increment - nothing to do! } double initAngle, currAngleInc; // choose angle increment so that each segment has equal length initAngle = 0.0; currAngleInc = totalAngle / nSegs; double currAngle = initAngle; Coordinate pt = new Coordinate(); while (currAngle < totalAngle) { double angle = startAngle + directionFactor * currAngle; pt.X = p.X + radius * Math.Cos(angle); pt.Y = p.Y + radius * Math.Sin(angle); _vertexList.AddPt(pt); currAngle += currAngleInc; } }
private static bool IsAllOrientationsEqual(Coordinate[] pts) { var orient = new OrientationIndex[3]; orient[0] = Orientation.Index(pts[0], pts[1], pts[2]); orient[1] = Orientation.Index(pts[1], pts[2], pts[0]); orient[2] = Orientation.Index(pts[2], pts[0], pts[1]); return(orient[0] == orient[1] && orient[0] == orient[2]); }
private static LogEventPropertyValue WriteCoordinateSequence( CoordinateSequence?sequence, bool multiple, OrientationIndex orientation = OrientationIndex.None ) { if (sequence == null) { return(new ScalarValue(null)); } var values = new List <LogEventPropertyValue>(); if (multiple) { if ((orientation == OrientationIndex.Clockwise && Orientation.IsCCW(sequence)) || (orientation == OrientationIndex.CounterClockwise && !Orientation.IsCCW(sequence))) { CoordinateSequences.Reverse(sequence); } } var hasZ = sequence.HasZ; for (var i = 0; i < sequence.Count; i++) { var value = new List <LogEventPropertyValue>(3); value.Add(new ScalarValue(sequence.GetX(i))); value.Add(new ScalarValue(sequence.GetY(i))); if (hasZ) { var z = sequence.GetZ(i); if (!double.IsNaN(z)) { value.Add(new ScalarValue(z)); } } if (multiple) { values.Add(new SequenceValue(value)); } else { values = value; break; } } return(new SequenceValue(values)); }
/// <summary> /// Simplify the input coordinate list. /// </summary> /// <remarks> /// If the distance tolerance is positive, concavities on the LEFT side of the line are simplified. /// If the supplied distance tolerance is negative, concavities on the RIGHT side of the line are simplified. /// </remarks> /// <param name="distanceTol">Simplification distance tolerance to use</param> /// <returns> /// The simplified coordinates list /// </returns> public Coordinate[] Simplify(double distanceTol) { _distanceTol = System.Math.Abs(distanceTol); if (distanceTol < 0) { _angleOrientation = OrientationIndex.Clockwise; } // rely on fact that boolean array is filled with false value _isDeleted = new byte[_inputLine.Length]; bool isChanged; do { isChanged = DeleteShallowConcavities(); } while (isChanged); return(CollapseLine()); }
/// <summary> /// Re-orients an orientation. /// </summary> /// <param name="orientation">The orientation</param> /// <returns></returns> public static OrientationIndex ReOrient(OrientationIndex orientation) { return((OrientationIndex)(-(int)orientation)); }
public float EventGetOrientation64(IntPtr evt, OrientationIndex index) { // Contract.Requires<ArgumentException>(evt != IntPtr.Zero, "The pointer to the event must be set."); return(default(float)); }
private static extern float event_get_orientation_64(IntPtr evt, OrientationIndex index);
protected static float GetEventOrientation(IntPtr evt, OrientationIndex index) { return(PlatformInvocation.Running32Bit ? event_get_orientation_32(evt, index) : event_get_orientation_64(evt, index)); }
public static extern float event_get_orientation(IntPtr evt, OrientationIndex index);
/// <inheritdoc /> public float GetEventOrientation(IntPtr evt, OrientationIndex index) { return(PlatformInvocation.Running32Bit ? _myoDeviceBridge.EventGetOrientation32(evt, index) : _myoDeviceBridge.EventGetOrientation64(evt, index)); }
public float EventGetOrientation64(IntPtr evt, OrientationIndex index) { Contract.Requires<ArgumentException>(evt != IntPtr.Zero, "The pointer to the event must be set."); return default(float); }
/// <inheritdoc /> public float EventGetOrientation64(IntPtr evt, OrientationIndex index) { return(event_get_orientation_64(evt, index)); }
/// <summary> /// Adds points for a circular fillet arc /// between two specified angles. /// The start and end point for the fillet are not added - /// the caller must add them if required. /// </summary> /// <param name="p">The center point</param> /// <param name="direction">Is -1 for a <see cref="OrientationIndex.Clockwise"/> angle, 1 for a <see cref="OrientationIndex.CounterClockwise"/> angle</param> /// <param name="startAngle">The start angle of the fillet</param> /// <param name="endAngle">The end angle of the fillet</param> /// <param name="radius">The radius of the fillet</param> private void AddDirectedFillet(Coordinate p, double startAngle, double endAngle, OrientationIndex direction, double radius) { int directionFactor = direction == OrientationIndex.Clockwise ? -1 : 1; double totalAngle = Math.Abs(startAngle - endAngle); int nSegs = (int)(totalAngle / _filletAngleQuantum + 0.5); if (nSegs < 1) { return; // no segments because angle is less than increment - nothing to do! } // choose angle increment so that each segment has equal length double angleInc = totalAngle / nSegs; var pt = new Coordinate(); for (int i = 0; i < nSegs; i++) { double angle = startAngle + directionFactor * i * angleInc; pt.X = p.X + radius * Math.Cos(angle); pt.Y = p.Y + radius * Math.Sin(angle); _segList.AddPt(pt); } }
/// <inheritdoc /> public float GetEventOrientation(IntPtr evt, OrientationIndex index) { return PlatformInvocation.Running32Bit ? _myoDeviceBridge.EventGetOrientation32(evt, index) : _myoDeviceBridge.EventGetOrientation64(evt, index); }
public float GetEventOrientation(IntPtr evt, OrientationIndex index) { Contract.Requires <ArgumentException>(evt != IntPtr.Zero, "The event handle must be set."); return(default(float)); }
/// <summary> /// Adds the offset points for an inside (concave) turn. /// </summary> /// <param name="orientation"></param> /// <param name="addStartPoint"></param> private void AddInsideTurn(OrientationIndex orientation, bool addStartPoint) { /** * add intersection point of offset segments (if any) */ _li.ComputeIntersection(_offset0.P0, _offset0.P1, _offset1.P0, _offset1.P1); if (_li.HasIntersection) { _segList.AddPt(_li.GetIntersection(0)); } else { /* * If no intersection is detected, * it means the angle is so small and/or the offset so * large that the offsets segments don't intersect. * In this case we must * add a "closing segment" to make sure the buffer curve is continuous, * fairly smooth (e.g. no sharp reversals in direction) * and tracks the buffer correctly around the corner. The curve connects * the endpoints of the segment offsets to points * which lie toward the centre point of the corner. * The joining curve will not appear in the final buffer outline, since it * is completely internal to the buffer polygon. * * In complex buffer cases the closing segment may cut across many other * segments in the generated offset curve. In order to improve the * performance of the noding, the closing segment should be kept as short as possible. * (But not too short, since that would defeat its purpose). * This is the purpose of the closingSegFactor heuristic value. */ /* * The intersection test above is vulnerable to robustness errors; i.e. it * may be that the offsets should intersect very close to their endpoints, * but aren't reported as such due to rounding. To handle this situation * appropriately, we use the following test: If the offset points are very * close, don't add closing segments but simply use one of the offset * points */ _hasNarrowConcaveAngle = true; //System.out.println("NARROW ANGLE - distance = " + distance); if (_offset0.P1.Distance(_offset1.P0) < _distance * InsideTurnVertexSnapDistanceFactor) { _segList.AddPt(_offset0.P1); } else { // add endpoint of this segment offset _segList.AddPt(_offset0.P1); /** * Add "closing segment" of required length. */ if (_closingSegLengthFactor > 0) { var mid0 = new Coordinate((_closingSegLengthFactor * _offset0.P1.X + _s1.X) / (_closingSegLengthFactor + 1), (_closingSegLengthFactor * _offset0.P1.Y + _s1.Y) / (_closingSegLengthFactor + 1)); _segList.AddPt(mid0); var mid1 = new Coordinate((_closingSegLengthFactor * _offset1.P0.X + _s1.X) / (_closingSegLengthFactor + 1), (_closingSegLengthFactor * _offset1.P0.Y + _s1.Y) / (_closingSegLengthFactor + 1)); _segList.AddPt(mid1); } else { /** * This branch is not expected to be used except for testing purposes. * It is equivalent to the JTS 1.9 logic for closing segments * (which results in very poor performance for large buffer distances) */ _segList.AddPt(_s1); } //*/ // add start point of next segment offset _segList.AddPt(_offset1.P0); } } }
private void WriteCoordinateSequence(Utf8JsonWriter writer, CoordinateSequence sequence, JsonSerializerOptions options, bool multiple = true, OrientationIndex orientation = OrientationIndex.None) { //writer.WritePropertyName("coordinates"); if (sequence == null) { writer.WriteNullValue(); return; } if (multiple) { writer.WriteStartArray(); if (orientation == OrientationIndex.Clockwise && Orientation.IsCCW(sequence) || orientation == OrientationIndex.CounterClockwise && !Orientation.IsCCW(sequence)) { CoordinateSequences.Reverse(sequence); } } bool hasZ = sequence.HasZ; for (int i = 0; i < sequence.Count; i++) { writer.WriteStartArray(); writer.WriteNumberValue(sequence.GetX(i)); writer.WriteNumberValue(sequence.GetY(i)); if (hasZ) { double z = sequence.GetZ(i); if (!double.IsNaN(z)) { writer.WriteNumberValue(sequence.GetZ(i)); } } writer.WriteEndArray(); if (!multiple) { break; } } if (multiple) { writer.WriteEndArray(); } }