How do you trigger the "Update COGO Attributes" programmatically immediately after the edit operation CopyLineFeaturesToParcelType?
I've tried this code, see attachement "Sample.txt"
In my case, the CanExecute is never true in both cases...
Note that the GridToGroundCorrection is ON, and both the Scale Factor and Offset direction are set, and my feature class is COGO Enabled.
Thank you,
Solved! Go to Solution.
hi Pascal,
Here are the functions. Note there is a slight signature change with addition of the spatial reference parameter. I edited, in place, the calling code in the previous comment:
private bool GetCOGOFromGeometry(Polyline myLineFeature, SpatialReference MapSR, double ScaleFactor, double DirectionOffset, out object[] COGODirectionDistanceRadiusArcLength)
{
COGODirectionDistanceRadiusArcLength = new object[4] { DBNull.Value,DBNull.Value,DBNull.Value, DBNull.Value };
try
{
COGODirectionDistanceRadiusArcLength[0] = DBNull.Value;
COGODirectionDistanceRadiusArcLength[1] = DBNull.Value;
var GeomSR= myLineFeature.SpatialReference;
if (GeomSR.IsGeographic && MapSR.IsGeographic)
return false; //no SDK support for Geodesics till 2.8
double UnitConversion = 1;
if (GeomSR.IsGeographic && MapSR.IsProjected)
{ //only need to project if dataset is in a GCS.
UnitConversion = MapSR.Unit.ConversionFactor; // Meters per unit. Only need this for converting to metric for GCS datasets.
myLineFeature = GeometryEngine.Instance.Project(myLineFeature, MapSR) as Polyline;
}
EllipticArcSegment pCircArc;
ICollection<Segment> LineSegments = new List<Segment>();
myLineFeature.GetAllSegments(ref LineSegments);
int numSegments = LineSegments.Count;
IList<Segment> iList = LineSegments as IList<Segment>;
Segment FirstSeg = iList[0];
Segment LastSeg = iList[numSegments - 1];
var pLine = LineBuilder.CreateLineSegment(FirstSeg.StartCoordinate, LastSeg.EndCoordinate);
COGODirectionDistanceRadiusArcLength[0] =
PolarRadiansToNorthAzimuthDecimalDegrees(pLine.Angle - DirectionOffset*Math.PI/180);
COGODirectionDistanceRadiusArcLength[1] = pLine.Length * UnitConversion / ScaleFactor;
//check if the last segment is a circular arc
var pCircArcLast = LastSeg as EllipticArcSegment;
if (pCircArcLast == null)
return true; //we already know there is no circluar arc COGO
//Keep a copy of the center point
var LastCenterPoint = pCircArcLast.CenterPoint;
COGODirectionDistanceRadiusArcLength[2] = pCircArcLast.IsCounterClockwise ?
-pCircArcLast.SemiMajorAxis : Math.Abs(pCircArcLast.SemiMajorAxis); //radius
double dArcLengthSUM = 0;
//use 30 times xy tolerance for circular arc segment tangency test
double dTangencyToleranceTest = MapSR.XYTolerance * 30; //around 3cms if using default XY Tolerance - recommended
for (int i = 0; i < numSegments; i++)
{
pCircArc = iList[i] as EllipticArcSegment;
if (pCircArc == null)
{
COGODirectionDistanceRadiusArcLength[2] = DBNull.Value; //radius
COGODirectionDistanceRadiusArcLength[3] = DBNull.Value; //arc length
return true;
}
var tolerance = LineBuilder.CreateLineSegment(LastCenterPoint, pCircArc.CenterPoint).Length;
if (tolerance > dTangencyToleranceTest)
{
COGODirectionDistanceRadiusArcLength[2] = DBNull.Value; //radius
COGODirectionDistanceRadiusArcLength[3] = DBNull.Value; //arc length
return true;
}
dArcLengthSUM += pCircArc.Length; //arc length sum
}
//now check to see if the radius and arclength survived and if so, clear the distance
if (COGODirectionDistanceRadiusArcLength[2] != DBNull.Value)
COGODirectionDistanceRadiusArcLength[1] = DBNull.Value;
COGODirectionDistanceRadiusArcLength[3] = dArcLengthSUM * UnitConversion / ScaleFactor;
COGODirectionDistanceRadiusArcLength[2] = (double)COGODirectionDistanceRadiusArcLength[2] * UnitConversion / ScaleFactor;
return true;
}
catch
{
return false;
}
}
Here is the second function for direction unit/format conversions from polar to north azimuth:
private static double PolarRadiansToNorthAzimuthDecimalDegrees(double InPolarRadians)
{
var AngConv = DirectionUnitFormatConversion.Instance;
var ConvDef = new ConversionDefinition()
{
DirectionTypeIn = ArcGIS.Core.SystemCore.DirectionType.Polar,
DirectionUnitsIn = ArcGIS.Core.SystemCore.DirectionUnits.Radians,
DirectionTypeOut = ArcGIS.Core.SystemCore.DirectionType.NorthAzimuth,
DirectionUnitsOut = ArcGIS.Core.SystemCore.DirectionUnits.DecimalDegrees
};
return AngConv.ConvertToDouble(InPolarRadians, ConvDef);
}
Hi Pascal,
Below is a snippet of code to programmatically assign the COGO values. The function called GetCOGOFromGeometry is not yet complete, but this should help to get you started on the right track.
Note, all of this and more will be covered in the Dev Summit during the session called: ArcGIS Pro SDK for .NET: Introduction to the Parcel Fabric API, on 8th April.
As you are probably aware, there is also SDK content here. I just mention it for the benefit of others reading this post.
Once it's ready I will also share the code for the function.
-Tim
ParcelEditToken peToken = editOper.CopyLineFeaturesToParcelType(srcFeatLyr, ids,
destLineL, destPolygonL);
if(!editOper.Execute())
return editOper.ErrorMessage;
//collect ground to grid correction values
var mapView = MapView.Active;
if (mapView?.Map == null)
return "";
var pSpatRef = mapView.Map.SpatialReference;
var cimDefinition = mapView.Map?.GetDefinition();
if (cimDefinition == null) return "";
var cimG2G = cimDefinition.GroundToGridCorrection;
double dScaleFactor = cimG2G.GetConstantScaleFactor();
double dDirectionOffsetCorrection = cimG2G.GetDirectionOffset();
var editOper2 = editOper.CreateChainedOperation();
var FeatSetCreated = peToken.CreatedFeatures;
Dictionary<string, object> ParcelLineAttributes = new Dictionary<string, object>();
if (FeatSetCreated != null)
{
foreach (KeyValuePair<MapMember, List<long>> kvp in FeatSetCreated)
{
if (kvp.Key == destPolygonL)
continue; //skip polygons, we just want to work with the lines
foreach (long oid in kvp.Value)
{
var insp = kvp.Key.Inspect(oid);
Polyline lineGeom = (Polyline)insp["SHAPE"];
object[] COGODirectionDistanceRadiusArcLength;
if (!GetCOGOFromGeometry(lineGeom, pSpatRef, dScaleFactor, dDirectionOffsetCorrection, out COGODirectionDistanceRadiusArcLength))
{
editOper2.Abort();
return "";
}
ParcelLineAttributes.Add("Direction", COGODirectionDistanceRadiusArcLength[0]);
ParcelLineAttributes.Add("Distance", COGODirectionDistanceRadiusArcLength[1]);
ParcelLineAttributes.Add("Radius", COGODirectionDistanceRadiusArcLength[2]);
ParcelLineAttributes.Add("ArcLength", COGODirectionDistanceRadiusArcLength[3]);
ParcelLineAttributes.Add("Rotation", dDirectionOffsetCorrection);
ParcelLineAttributes.Add("Scale", dScaleFactor);
ParcelLineAttributes.Add("IsCOGOGround", 1);
editOper2.Modify(kvp.Key, oid, ParcelLineAttributes);
ParcelLineAttributes.Clear();
}
editOper2.Execute();
}
}
Good day Tim,
Thank you for the reply.
This function GetCOGOFromGeometry will be available in the next API release 2.7.2 or 2.8?
Regards,
Pascal
Pascal, the function will be shared either today, tomorrow, or early next week. It is written, but needs some testing. Note that you have access to the full geometry API, and the lines in the parcel fabric are standard line features. For example, below is a code snippet to return the info for the straight line between the first and last vertex of the feature.
-Tim
ICollection<Segment> LineSegments = new List<Segment>();
myLineFeature.GetAllSegments(ref LineSegments);
int numSegments = LineSegments.Count;
IList<Segment> iList = LineSegments as IList<Segment>;
Segment FirstSeg = iList[0];
Segment LastSeg = iList[numSegments - 1];
var pLine = LineBuilder.CreateLineSegment(FirstSeg.StartCoordinate, LastSeg.EndCoordinate);
var dDirectionPolarRadians = pLine.Angle;
var dDistance = pLine.Length;
hi Pascal,
Here are the functions. Note there is a slight signature change with addition of the spatial reference parameter. I edited, in place, the calling code in the previous comment:
private bool GetCOGOFromGeometry(Polyline myLineFeature, SpatialReference MapSR, double ScaleFactor, double DirectionOffset, out object[] COGODirectionDistanceRadiusArcLength)
{
COGODirectionDistanceRadiusArcLength = new object[4] { DBNull.Value,DBNull.Value,DBNull.Value, DBNull.Value };
try
{
COGODirectionDistanceRadiusArcLength[0] = DBNull.Value;
COGODirectionDistanceRadiusArcLength[1] = DBNull.Value;
var GeomSR= myLineFeature.SpatialReference;
if (GeomSR.IsGeographic && MapSR.IsGeographic)
return false; //no SDK support for Geodesics till 2.8
double UnitConversion = 1;
if (GeomSR.IsGeographic && MapSR.IsProjected)
{ //only need to project if dataset is in a GCS.
UnitConversion = MapSR.Unit.ConversionFactor; // Meters per unit. Only need this for converting to metric for GCS datasets.
myLineFeature = GeometryEngine.Instance.Project(myLineFeature, MapSR) as Polyline;
}
EllipticArcSegment pCircArc;
ICollection<Segment> LineSegments = new List<Segment>();
myLineFeature.GetAllSegments(ref LineSegments);
int numSegments = LineSegments.Count;
IList<Segment> iList = LineSegments as IList<Segment>;
Segment FirstSeg = iList[0];
Segment LastSeg = iList[numSegments - 1];
var pLine = LineBuilder.CreateLineSegment(FirstSeg.StartCoordinate, LastSeg.EndCoordinate);
COGODirectionDistanceRadiusArcLength[0] =
PolarRadiansToNorthAzimuthDecimalDegrees(pLine.Angle - DirectionOffset*Math.PI/180);
COGODirectionDistanceRadiusArcLength[1] = pLine.Length * UnitConversion / ScaleFactor;
//check if the last segment is a circular arc
var pCircArcLast = LastSeg as EllipticArcSegment;
if (pCircArcLast == null)
return true; //we already know there is no circluar arc COGO
//Keep a copy of the center point
var LastCenterPoint = pCircArcLast.CenterPoint;
COGODirectionDistanceRadiusArcLength[2] = pCircArcLast.IsCounterClockwise ?
-pCircArcLast.SemiMajorAxis : Math.Abs(pCircArcLast.SemiMajorAxis); //radius
double dArcLengthSUM = 0;
//use 30 times xy tolerance for circular arc segment tangency test
double dTangencyToleranceTest = MapSR.XYTolerance * 30; //around 3cms if using default XY Tolerance - recommended
for (int i = 0; i < numSegments; i++)
{
pCircArc = iList[i] as EllipticArcSegment;
if (pCircArc == null)
{
COGODirectionDistanceRadiusArcLength[2] = DBNull.Value; //radius
COGODirectionDistanceRadiusArcLength[3] = DBNull.Value; //arc length
return true;
}
var tolerance = LineBuilder.CreateLineSegment(LastCenterPoint, pCircArc.CenterPoint).Length;
if (tolerance > dTangencyToleranceTest)
{
COGODirectionDistanceRadiusArcLength[2] = DBNull.Value; //radius
COGODirectionDistanceRadiusArcLength[3] = DBNull.Value; //arc length
return true;
}
dArcLengthSUM += pCircArc.Length; //arc length sum
}
//now check to see if the radius and arclength survived and if so, clear the distance
if (COGODirectionDistanceRadiusArcLength[2] != DBNull.Value)
COGODirectionDistanceRadiusArcLength[1] = DBNull.Value;
COGODirectionDistanceRadiusArcLength[3] = dArcLengthSUM * UnitConversion / ScaleFactor;
COGODirectionDistanceRadiusArcLength[2] = (double)COGODirectionDistanceRadiusArcLength[2] * UnitConversion / ScaleFactor;
return true;
}
catch
{
return false;
}
}
Here is the second function for direction unit/format conversions from polar to north azimuth:
private static double PolarRadiansToNorthAzimuthDecimalDegrees(double InPolarRadians)
{
var AngConv = DirectionUnitFormatConversion.Instance;
var ConvDef = new ConversionDefinition()
{
DirectionTypeIn = ArcGIS.Core.SystemCore.DirectionType.Polar,
DirectionUnitsIn = ArcGIS.Core.SystemCore.DirectionUnits.Radians,
DirectionTypeOut = ArcGIS.Core.SystemCore.DirectionType.NorthAzimuth,
DirectionUnitsOut = ArcGIS.Core.SystemCore.DirectionUnits.DecimalDegrees
};
return AngConv.ConvertToDouble(InPolarRadians, ConvDef);
}
With 2.9 we now have new SDK documentation content on COGO API topics:
https://github.com/esri/arcgis-pro-sdk/wiki/ProConcepts-COGO
For the latest code for Update COGO, including access and use of the map’s ground to grid corrections, see the Parcel Utilities Add-in.
Install: https://arcg.is/0f5reS
Code: https://github.com/Esri/parcel-fabric-pro-addins/tree/main/ParcelsAddin
The configuration settings are designed to protect against the overwriting of good COGO:
These settings are saved between Pro sessions.
-Tim