Offset Polyline(original as drawn) problem in Arcgis pro sdk

2532
13
12-12-2017 11:34 PM
tanerkoka
Occasional Contributor II

Hi,

We have a offset polyline problem I can not offset polyline as you draw (original as drawn) . How can we solve this important problem ? Or are there any alternative solution? We are using all Offset Types (Mitter ,Bevel , Round , Square) but polyline shape changes,  we don not want the line to be different shape  .We can offset same polyline in  ArcObjects but we can not wit ArcgisPro SDK.

Here is in code and pictures in ArcgisPro SDK below :

Mitter left and  right offset in the middle green polyline is original polyline

if (result.RightSide)
offsetGeometry = GeometryEngine.Instance.Offset(feature.GetShape(), distance, OffsetType.Miter, 5) as Polyline;
else
offsetGeometry = GeometryEngine.Instance.Offset(feature.GetShape(), -distance, OffsetType.Miter, 5) as Polyline;

Miter Ofset

Round left and right offset in the middle green polyline is original polyline

if (result.RightSide)
offsetGeometry = GeometryEngine.Instance.Offset(feature.GetShape(), distance, OffsetType.Round, 0) as Polyline;
else
offsetGeometry = GeometryEngine.Instance.Offset(feature.GetShape(), -distance, OffsetType.Round, 0) as Polyline;

Round offset

Here is below what we want correct left and right offset code and pictures in ArcObjects :

Left and  right offset in the middle green polyline is original polyline.

IConstructCurve constructCurve = new PolylineClass();

constructCurve.ConstructOffset(polycurve, Offset, ref esriConstructOffsetEnum, ref bevelRatio);

ArcObjects Offset

Thanks for Helping 

0 Kudos
13 Replies
trushar
New Contributor II

Hello Annette, any word on the above?

While you are at it, I like to find out additional information on the following method "GeometryEngine.Instance.SideBuffer()", if you have any updates please?

Noticed that the LineCapType throws not implemented. See line number ~4820 in "ArcGIS.Core.Geometry.GeometryEngine

Decompiled code snip from your nuget package:

public ArcGIS.Core.Geometry.Geometry SideBuffer(
Polyline polyline,
double distance,
LeftOrRightSide side,
LineCapType capType)
{
GeometryEngine.CheckForNullGeometry((ArcGIS.Core.Geometry.Geometry) polyline);
if (double.IsNaN(distance) || double.IsInfinity(distance) || distance < 0.0)
throw new ArgumentException("distance must be greater than zero");
if (capType == LineCapType.Square)
throw new ArgumentException(string.Format(GeometryResources.NotImplemented, (object) "LineCapType.Square"));

 

 

0 Kudos
AnnetteLocke
Esri Contributor

This is a bug that will be addressed in a future release. Unfortunately, I can't give you an exact date at this time. I am working on a workaround for you, but I want to test it a little bit more. It will be ready tomorrow. 

Regarding SideBuffer, the corners of the buffer will always be round. The LineCapType refers only to the start and end of the line. 

 

0 Kudos
AnnetteLocke
Esri Contributor

Can you use this workaround? 

private Multipart GetOffsetUsingGraphicBuffer(Multipart multipart, double offsetDistance, LineJoinType joinType)
{
  Polygon graphicBuffer = GeometryEngine.Instance.GraphicBuffer(multipart, Math.Abs(offsetDistance), joinType, LineCapType.Square, 4, 0, 96) as Polygon;

  Polyline boundary = GeometryEngine.Instance.Boundary(graphicBuffer) as Polyline;

  ProximityResult startResult = GeometryEngine.Instance.NearestPoint(boundary, multipart.Points[0]);
  Coordinate2D coord = (Coordinate2D)(startResult.Point);
  Segment firstSegment = multipart.Parts[0][0];

  // Negative offset distance means the offset line will be on the left side
  bool isOnRightSide = PointIsOnRightSide(firstSegment.StartCoordinate, coord, firstSegment.EndCoordinate);
  if (offsetDistance > 0 && !isOnRightSide)
    coord.Rotate(Math.PI, (Coordinate2D)(multipart.Points[0]));

  double distanceAlongCurve1, distanceFromCurve;
  LeftOrRightSide whichSide;
  MapPoint point = GeometryEngine.Instance.QueryPointAndDistance(boundary, SegmentExtensionType.NoExtension, coord.ToMapPoint(), AsRatioOrLength.AsRatio, out distanceAlongCurve1, out distanceFromCurve, out whichSide);

  ProximityResult endResult = GeometryEngine.Instance.NearestPoint(boundary, multipart.Points.Last());
  coord = (Coordinate2D)(endResult.Point);
  if (offsetDistance > 0 && !isOnRightSide)
    coord.Rotate(Math.PI, (Coordinate2D)(multipart.Points.Last()));

  double distanceAlongCurve2;
  point = GeometryEngine.Instance.QueryPointAndDistance(boundary, SegmentExtensionType.NoExtension, coord.ToMapPoint(), AsRatioOrLength.AsRatio, out distanceAlongCurve2, out distanceFromCurve, out whichSide);

  double d1 = Math.Min(distanceAlongCurve1, distanceAlongCurve2);
  double d2 = Math.Max(distanceAlongCurve1, distanceAlongCurve2);

  Polyline subCurve = GeometryEngine.Instance.GetSubCurve(boundary, d1, d2, AsRatioOrLength.AsRatio) as Polyline;
  return subCurve;
}

private bool PointIsOnRightSide(Coordinate2D origin, Coordinate2D p1, Coordinate2D p2)
{
  // The result is positive if p1 lies on right side of origin-->p2;

  double part1 = (p1.X - origin.X) * (p2.Y - origin.Y),
         part2 = (p1.Y - origin.Y) * (p2.X - origin.X),
         result = part1 - part2;

  return result > 0;
}

// Here is a test
public void GEOffsetWorkaroundTest()
{
  SpatialReference spatialReference = SpatialReferences.WGS84;

  var coords = new List<Coordinate2D>
  {
      new Coordinate2D(0.1, 0.1),
      new Coordinate2D(0.2, 0.5),
      new Coordinate2D(0.3, 0.1),
      new Coordinate2D(0.4, 0.1),
      new Coordinate2D(0.5, 0.8)
  };

  Polyline polyline = PolylineBuilderEx.CreatePolyline(coords, spatialReference) as Polyline;

  Polyline outputOffsetPolyline = GetOffsetUsingGraphicBuffer(polyline, 0.1, LineJoinType.Miter) as Polyline;
  File.WriteAllText("C:\\temp\\outputOffsetPolyline_1_.txt", outputOffsetPolyline.ToJson());

  outputOffsetPolyline = GetOffsetUsingGraphicBuffer(polyline, -0.1, LineJoinType.Miter) as Polyline;
  File.WriteAllText("C:\\temp\\outputOffsetPolyline_2_.txt", outputOffsetPolyline.ToJson());

  outputOffsetPolyline = GetOffsetUsingGraphicBuffer(polyline, 0.1, LineJoinType.Bevel) as Polyline;
  File.WriteAllText("C:\\temp\\outputOffsetPolyline_3_.txt", outputOffsetPolyline.ToJson());

  outputOffsetPolyline = GetOffsetUsingGraphicBuffer(polyline, -0.1, LineJoinType.Bevel) as Polyline;
  File.WriteAllText("C:\\temp\\outputOffsetPolyline_4_.txt", outputOffsetPolyline.ToJson());

  outputOffsetPolyline = GetOffsetUsingGraphicBuffer(polyline, 0.1, LineJoinType.Round) as Polyline;
  File.WriteAllText("C:\\temp\\outputOffsetPolyline_5_.txt", outputOffsetPolyline.ToJson());
}
0 Kudos
AnnetteLocke
Esri Contributor

Hi,

This will be fixed in the ArcGIS Pro 3.3.

Annette

0 Kudos