4 votos

¿El método IPolygon2.QueryExteriorRingsEx no funciona en ArcGIS versión 10.1 SP1?

Estoy actualizando mis addins de 10.0 a 10.1 y mi código está fallando en el método IPolygon2.QueryExteriorRingsEx.

Entiendo que hay algo extraño en este método porque Ayuda al desarrollador dice que no funciona en C# .Net (Ver observaciones: "No funciona en .NET. Use Polygon4.get_InteriorRingBag en su lugar"). En las observaciones también dice que este método sólo acepta un array de tipo IRing para exteriorRings. Usar un array de IRing2 no funcionará. Estoy usando iRing.

Todo funcionaba muy bien en la versión 10.0, pero ahora el método se bloquea si intento consultar más que un solo anillo exterior. (La consulta de un polígono con un anillo exterior pasa)

¿Puede alguien confirmar este comportamiento antes de que intente reescribir este procedimiento utilizando el método Polygon4.get_InteriorRingBag en su lugar?

Procedimiento siguiente - la línea del problema está dentro del bucle do while

Public Sub PolygonsToPolylines(ByVal sourceFeatureLayer As ESRI.ArcGIS.Carto.IFeatureLayer, ByVal destFeatureLayer As ESRI.ArcGIS.Carto.IFeatureLayer)
On Error GoTo trap

    Dim MxApplication As ESRI.ArcGIS.ArcMapUI.IMxApplication = TryCast(My.ArcMap.Application, ESRI.ArcGIS.ArcMapUI.IMxApplication)

    Dim pEditor As ESRI.ArcGIS.Editor.IEditor2
    Dim pEditLayers As ESRI.ArcGIS.Editor.IEditLayers
    Dim pActiveView As ESRI.ArcGIS.Carto.IActiveView
    Dim pEnumFeature As ESRI.ArcGIS.Geodatabase.IEnumFeature
    Dim pFeature As ESRI.ArcGIS.Geodatabase.IFeature
    Dim pPolygon As ESRI.ArcGIS.Geometry.IPolygon2
    Dim pTempPolyline As ESRI.ArcGIS.Geometry.ITopologicalOperator
    Dim pNewFeature As ESRI.ArcGIS.Geodatabase.IFeature
    Dim pPolygon2 As ESRI.ArcGIS.Geometry.IPolygon2
    Dim pPolyline As ESRI.ArcGIS.Geometry.IPolyline
    Dim pPolylinePointColl As ESRI.ArcGIS.Geometry.IPointCollection
    Dim pRings() As ESRI.ArcGIS.Geometry.IRing
    Dim pRing As ESRI.ArcGIS.Geometry.IRing
    Dim pRings2() As ESRI.ArcGIS.Geometry.IRing
    Dim pRing2 As ESRI.ArcGIS.Geometry.IRing

    'new
    Dim pFeatureSelection As ESRI.ArcGIS.Carto.IFeatureSelection
    Dim pSelectionSet As ESRI.ArcGIS.Geodatabase.ISelectionSet
    Dim pFeatureCursor As ESRI.ArcGIS.Geodatabase.IFeatureCursor = Nothing

    Dim r As Long, i2 As Long, r2 As Long, c As Long, c2 As Long
    Dim d As Long 'progress dialog counter

    Dim source3D As Boolean, dest3D As Boolean

    Has_3D_value(sourceFeatureLayer.FeatureClass, source3D) 'determine whether source features class is 3D
    Has_3D_value(destFeatureLayer.FeatureClass, dest3D) 'determine whether destination features class is 3D

    'Get a handle to the Editor extension
    pEditor = GetEditorFromArcMap(MxApplication)

    If pEditor Is Nothing Then Exit Sub

    pEditLayers = pEditor 'QI
    pActiveView = pEditor.Map

    If pEditor.EditState = ESRI.ArcGIS.Editor.esriEditState.esriStateNotEditing Then
        MsgBox("You must be editing to use this feature!", MsgBoxStyle.Information)
       Exit Sub
    End If

    'QUERY Layer selection to get cursor'''''''''''''''''''''''''''''''''''''''''''''''
    pFeatureSelection = sourceFeatureLayer

    pSelectionSet = pFeatureSelection.SelectionSet
    d = pSelectionSet.Count
    If d < 1 Then
        MsgBox("You must select at least 1 feature!") : Exit Sub
    End If

    'retreive selection into a cursor
    pSelectionSet.Search(Nothing, False, pFeatureCursor)
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

    'Set up Progress Bar''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

    'Create a CancelTracker
    'Dim trackCancel As ESRI.ArcGIS.esriSystem.ITrackCancel = New ESRI.ArcGIS.Display.CancelTrackerClass '10.0 
    Dim trackCancel As ESRI.ArcGIS.esriSystem.ITrackCancel = New ESRI.ArcGIS.Display.CancelTracker '10.1 update

    Dim progressDialogFactory As ESRI.ArcGIS.Framework.IProgressDialogFactory = New ESRI.ArcGIS.Framework.ProgressDialogFactoryClass

    'Set the properties of the Step Progressor
    Dim int32_hWnd As System.Int32 = My.ArcMap.Application.hWnd
    Dim stepProgressor As ESRI.ArcGIS.esriSystem.IStepProgressor = progressDialogFactory.Create(trackCancel, int32_hWnd)
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

    'Set the properties of the Step Progressor
    stepProgressor.MinRange = 0
    stepProgressor.MaxRange = d
    stepProgressor.StepValue = 1
    stepProgressor.Message = "Copying..."

    'Create the ProgressDialog. This automatically displays the dialog
    Dim progressDialog2 As ESRI.ArcGIS.Framework.IProgressDialog2 = CType(stepProgressor, ESRI.ArcGIS.Framework.IProgressDialog2) ' Explict Cast

    ' Set the properties of the ProgressDialog
    progressDialog2.CancelEnabled = True
    progressDialog2.Description = "Copy Features"
    progressDialog2.Title = "Copying..."
    progressDialog2.Animation = ESRI.ArcGIS.Framework.esriProgressAnimationTypes.esriDownloadFile
    ' Step. Do your big process here.
    Dim boolean_Continue As System.Boolean
    boolean_Continue = True
    Dim i As System.Int32
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

    'Start an edit operation
    pEditor.StartOperation()

    pFeature = pFeatureCursor.NextFeature

    Do While Not pFeature Is Nothing

        'Progress Bar''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
        Dim statusBar As ESRI.ArcGIS.esriSystem.IStatusBar = TryCast(My.ArcMap.Application.StatusBar, ESRI.ArcGIS.esriSystem.IStatusBar)
        statusBar.Message(0) = i.ToString
        '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

        If pFeature.Shape.GeometryType = ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolygon Then
            c = c + 1
            pPolygon2 = pFeature.ShapeCopy
            SimplifyGeometry(pPolygon2)

            r = pPolygon2.ExteriorRingCount
            If r > 0 Then
                 r = r - 1
                ReDim pRings(r)
                pPolygon2.QueryExteriorRingsEx(pPolygon2.ExteriorRingCount, pRings(0))

                For i = 0 To r
                    pRing = pRings(i)

                    r2 = pPolygon2.InteriorRingCount(pRing)

                    If r2 > 0 Then
                        r2 = r2 - 1
                        ReDim pRings2(r2)
                        pPolygon2.QueryInteriorRingsEx(pRing, pPolygon2.InteriorRingCount(pRing), pRings2(0))
                        For i2 = 0 To r2
                            pRing2 = pRings2(i2)

                            pPolylinePointColl = New ESRI.ArcGIS.Geometry.Polyline
                            pPolylinePointColl.AddPointCollection(pRing2)
                            pPolyline = pPolylinePointColl 'QI
                            SimplifyGeometry(pPolyline)

                            SimplifyGeometry(pPolyline)
                            pNewFeature = destFeatureLayer.FeatureClass.CreateFeature
                            pNewFeature.Shape = pPolyline
                            CopyFieldValues(pFeature, pNewFeature) 'copy matching field values
                            pNewFeature.Store()
                            c2 = c2 + 1
                        Next
                    End If

                    pPolylinePointColl = New ESRI.ArcGIS.Geometry.Polyline
                    pPolylinePointColl.AddPointCollection(pRing)
                    pPolyline = pPolylinePointColl 'QI
                    SimplifyGeometry(pPolyline)

                    pNewFeature = destFeatureLayer.FeatureClass.CreateFeature

                    If (dest3D = True And source3D = False) Or (dest3D = True And source3D = True) Then
                        SetZAware(pPolyline) 'make geometry zAware
                        'FUTURE UPDATE = COPY or ASSIGN 3D Values to all geometry points
                    End If

                    If dest3D = False And source3D = True Then
                        RemoveZAware(pPolyline) 'remove zAware from geometry
                    End If

                    pNewFeature.Shape = pPolyline
                    CopyFieldValues(pFeature, pNewFeature) 'copy matching field values
                    pNewFeature.Store()
                    c2 = c2 + 1

                    'Check if the cancel button was pressed. If so, stop process
                    boolean_Continue = trackCancel.Continue
                    If Not boolean_Continue Then
                      Exit For
                    End If
                Next
            End If

        End If

        pFeature = pFeatureCursor.NextFeature
    Loop

    'Done
    trackCancel = Nothing
    stepProgressor = Nothing
    progressDialog2.HideDialog()
    progressDialog2 = Nothing

    MsgBox("Succesfully created " & c2 & " lines from " & c & " selected polygons.")

    'Complete the edit operation
    pEditor.StopOperation("Copy Polygons to Polylines")

    'Flag the area of the new feature for refreshing
    pActiveView.Refresh()

    Exit Sub

trap:
    MsgBox(Err.Description)
    pEditor.AbortOperation()

CancelProgressBar:
    'Progress cleanup
    progressDialog2.HideDialog()
    trackCancel = Nothing
    stepProgressor = Nothing
    progressDialog2 = Nothing

End Sub

0 votos

El enlace va a la ayuda de la 9.1. La ayuda de la 10.1 (no he comprobado las versiones anteriores) sí incluye esa observación. No estoy seguro de que este enlace funcione, pero... resources.arcgis.com/es/help/arcobjects-net/componenthelp/

3voto

auramo Puntos 161

En 10.1 SP1, soy capaz de reproducir el System.ExecutionEngineException (que aparentemente no se puede corregir) se bloquea si tengo como objetivo .NET 3.5 y utilizo un polígono que tiene múltiples anillos exteriores con IPolygon2.QueryExteriorRingsEx . Funciona bien para los polígonos exteriores de un solo anillo.

Si me dirijo a .NET 4.0 puedo utilizar QueryExteriorRingsEx sin problemas para polígonos con múltiples anillos exteriores.

Pude utilizar IPolygon4.ExteriorRingBag y InteriorRingBag sin problemas en ambas versiones del framework.

También probé en 10.0 SP5 y encontré que QueryExteriorRingsEx funciona bien tanto en .NET 3.5 como en .NET 4.0.

Este es el código C# con el que he probado ( LINQPad versiones aquí (10.1) y aquí (10.0):

using System;
using System.Collections.Generic;
using System.Linq;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Geometry;

namespace RingTest1
{
    class Program
    {
        [STAThread()]
        static void Main(string[] args)
        {
            if (ESRI.ArcGIS.RuntimeManager.ActiveRuntime == null)
                ESRI.ArcGIS.RuntimeManager.BindLicense(ESRI.ArcGIS.ProductCode.EngineOrDesktop);

            var polygon1 = CreateSinglePartPolygon();
            var polygon2 = CreateDonutPolygon();
            var polygon3 = CreateMultiPartPolygon();
            Console.WriteLine(PolygonRingsToPolylines(polygon1).Count());
            Console.WriteLine(PolygonRingsToPolylines(polygon2).Count());
            Console.WriteLine(PolygonRingsToPolylines(polygon3).Count());
            Console.WriteLine(QueryExteriorRingsExTest(polygon1).Count());
            Console.WriteLine(QueryExteriorRingsExTest(polygon2).Count());
            Console.WriteLine(QueryExteriorRingsExTest(polygon3).Count());
        }

        private static IEnumerable<IRing> QueryExteriorRingsExTest(IPolygon polygon)
        {
            var polygon2 = (IPolygon2)polygon;
            IRing exteriorRings;
            polygon2.QueryExteriorRingsEx(polygon2.ExteriorRingCount, out exteriorRings);
            for (int i = 0; i < polygon2.ExteriorRingCount; i++)
            {
                yield return exteriorRings;
            }
        }

        private static IEnumerable<IPolyline> PolygonRingsToPolylines(IPolygon polygon)
        {
            var polygon4 = (IPolygon4)polygon;
            var exteriorRingGeometryBag = (IGeometryBag)polygon4.ExteriorRingBag;
            var exteriorRingGeometryCollection = (IGeometryCollection)exteriorRingGeometryBag;
            for (int i = 0; i < exteriorRingGeometryCollection.GeometryCount; i++)
            {
                var exteriorRingGeometry = exteriorRingGeometryCollection.get_Geometry(i);
                yield return SegmentCollectionToPolyline((ISegmentCollection)exteriorRingGeometry);

                var interiorRingGeometryBag = polygon4.get_InteriorRingBag((IRing)exteriorRingGeometry);
                var interiorRingGeometryCollection = (IGeometryCollection)interiorRingGeometryBag;
                for (int j = 0; j < interiorRingGeometryCollection.GeometryCount; j++)
                {
                    var interiorRingGeometry = interiorRingGeometryCollection.get_Geometry(i);
                    yield return SegmentCollectionToPolyline((ISegmentCollection)interiorRingGeometry);
                }
            }
        }

        private static IPolyline SegmentCollectionToPolyline(ISegmentCollection segmentCollection)
        {
            var polyline = (IPolyline)new PolylineClass();
            var geomcoll = (IGeometryCollection)polyline;
            var pathcoll = (ISegmentCollection)new PathClass();
            for (int i = 0; i < segmentCollection.SegmentCount; i++)
            {
                var segment = segmentCollection.get_Segment(i);
                pathcoll.AddSegment(segment);
            }
            geomcoll.AddGeometry((IGeometry)pathcoll);
            geomcoll.GeometriesChanged();
            return polyline;
        }

        private static IPolygon CreateSinglePartPolygon()
        {
            var polygon = (IPolygon)new PolygonClass();
            var pointcoll = (IPointCollection4)polygon;
            var geometryBridge2 = (IGeometryBridge2)new GeometryEnvironmentClass();
            var aWKSPointBuffer = new WKSPoint[5];

            // Exterior ring
            aWKSPointBuffer[0].X = 0;
            aWKSPointBuffer[0].Y = 0;
            aWKSPointBuffer[1].X = 0;
            aWKSPointBuffer[1].Y = 1;
            aWKSPointBuffer[2].X = 1;
            aWKSPointBuffer[2].Y = 1;
            aWKSPointBuffer[3].X = 1;
            aWKSPointBuffer[3].Y = 0;
            aWKSPointBuffer[4].X = 0;
            aWKSPointBuffer[4].Y = 0;
            geometryBridge2.AddWKSPoints(pointcoll, ref aWKSPointBuffer);

            var topoOp = (ITopologicalOperator2)polygon;
            topoOp.IsKnownSimple_2 = false;
            topoOp.Simplify();
            return polygon;
        }

        private static IPolygon CreateDonutPolygon()
        {
            var polygon = (IPolygon)new PolygonClass();
            var pointcoll = (IPointCollection4)polygon;
            var geometryBridge2 = (IGeometryBridge2)new GeometryEnvironmentClass();
            var aWKSPointBuffer = new WKSPoint[5];

            // Exterior ring
            aWKSPointBuffer[0].X = 0;
            aWKSPointBuffer[0].Y = 0;
            aWKSPointBuffer[1].X = 0;
            aWKSPointBuffer[1].Y = 4;
            aWKSPointBuffer[2].X = 4;
            aWKSPointBuffer[2].Y = 4;
            aWKSPointBuffer[3].X = 4;
            aWKSPointBuffer[3].Y = 0;
            aWKSPointBuffer[4].X = 0;
            aWKSPointBuffer[4].Y = 0;
            geometryBridge2.AddWKSPoints(pointcoll, ref aWKSPointBuffer);

            // Interior ring
            aWKSPointBuffer[0].X = 1;
            aWKSPointBuffer[0].Y = 1;
            aWKSPointBuffer[1].X = 3;
            aWKSPointBuffer[1].Y = 1;
            aWKSPointBuffer[2].X = 3;
            aWKSPointBuffer[2].Y = 3;
            aWKSPointBuffer[3].X = 1;
            aWKSPointBuffer[3].Y = 3;
            aWKSPointBuffer[4].X = 1;
            aWKSPointBuffer[4].Y = 1;
            geometryBridge2.AddWKSPoints(pointcoll, ref aWKSPointBuffer);

            var topoOp = (ITopologicalOperator2)polygon;
            topoOp.IsKnownSimple_2 = false;
            topoOp.Simplify();
            return polygon;
        }

        private static IPolygon CreateMultiPartPolygon()
        {
            var polygon = (IPolygon)new PolygonClass();
            var pointcoll = (IPointCollection4)polygon;
            var geometryBridge2 = (IGeometryBridge2)new GeometryEnvironmentClass();
            var aWKSPointBuffer = new WKSPoint[5];

            // Exterior ring 1
            aWKSPointBuffer[0].X = 0;
            aWKSPointBuffer[0].Y = 0;
            aWKSPointBuffer[1].X = 0;
            aWKSPointBuffer[1].Y = 1;
            aWKSPointBuffer[2].X = 1;
            aWKSPointBuffer[2].Y = 1;
            aWKSPointBuffer[3].X = 1;
            aWKSPointBuffer[3].Y = 0;
            aWKSPointBuffer[4].X = 0;
            aWKSPointBuffer[4].Y = 0;
            geometryBridge2.AddWKSPoints(pointcoll, ref aWKSPointBuffer);

            // Exterior ring 2
            aWKSPointBuffer[0].X = 2;
            aWKSPointBuffer[0].Y = 2;
            aWKSPointBuffer[1].X = 2;
            aWKSPointBuffer[1].Y = 3;
            aWKSPointBuffer[2].X = 3;
            aWKSPointBuffer[2].Y = 3;
            aWKSPointBuffer[3].X = 3;
            aWKSPointBuffer[3].Y = 2;
            aWKSPointBuffer[4].X = 2;
            aWKSPointBuffer[4].Y = 2;
            geometryBridge2.AddWKSPoints(pointcoll, ref aWKSPointBuffer);

            var topoOp = (ITopologicalOperator2)polygon;
            topoOp.IsKnownSimple_2 = false;
            topoOp.Simplify();
            return polygon;
        }
    }
}

Aquí está la salida del programa en 10.1 SP1 cuando se ejecuta sin depuración (después de cerrar el diálogo de bloqueo) y con el objetivo de .NET 3.5:

1
2
2
1
1

Unhandled Exception: System.BadImageFormatException: Array type not expected here.
   at ESRI.ArcGIS.Geometry.PolygonClass.QueryExteriorRingsEx(Int32 numExteriorRingsRequested, IRing& exteriorRings)
   at RingTest1.Program.d\_\_0.MoveNext() in C:\\CSProjects\\RingTest1\\RingTest1\\Program.cs:line 32
   at System.Linq.Enumerable.Count\[TSource\](IEnumerable\`1 source)
   at RingTest1.Program.Main(String\[\] args) in C:\\CSProjects\\RingTest1\\RingTest1\\Program.cs:line 25

Este es el resultado en .NET 4.0:

1
2
2
1
1
2

1 votos

+1 ¡Grandioso trabajo de investigación! Esto hace un buen caso para pasar a 4.0.

3voto

Nathan Bedford Puntos 3157

Tenga en cuenta que el IPolygon2.QueryExteriorRingsEx no es totalmente compatible con la conversión de COM a .NET: Se supone que debe devolver una referencia a un array, pero en .NET devuelve una referencia al primer elemento del array.

Compara esto con, por ejemplo, ISegmentCollection.QuerySegments vs IGeometryBridge.QuerySegments donde la firma de este último está adaptada para .NET.

La documentación para IPolygon2.QueryExteriorRingsEx afirma explícitamente:

No funciona en .NET. Utilice IPolygon4.ExteriorRingBag en su lugar.

Llamando a IPolygon2.QueryExteriorRingsEx puede funcionar en .NET 4.0, pero no confíe en ello. Este comportamiento depende de la forma en que los datos se marshallan y de cómo el CLR los mueve en la memoria. No se garantiza que sea consistente entre ejecuciones, versiones de Esri o iteraciones de .NET framework.

0 votos

Gracias Petr. Creo que la documentación dice que sólo no funciona en C#.

0 votos

Gracias por la explicación, me preguntaba por qué la firma no incluía la sintaxis del array.

0 votos

@Jakub, creo que mis pruebas junto con tus informes sugieren que la situación es la misma tanto para VB.NET como para C#. Al fin y al cabo ambos son .NET y el CLR tiene la última palabra sobre lo que funciona :)

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X