Excluding layers from snapping

1100
8
09-09-2011 06:17 AM
MarkCammarere
New Contributor III
I'm working with ArcObjects in C#, and am trying to exclude all map layers but one (the only one I want to snap to) from the snapping environment. I'm using the ISnappingEnvironment and IPointSnapper interfaces. I've put the following code in the OnClick method of the tool I'm using:

m_Snapper = m_SnappingEnvironment.PointSnapper;
ISet anExclLyrSet = new SetClass();
m_Snapper.ExcludedLayers(ref anExclLyrSet);
   ...loop through all map layers, adding all but the one of interest to anExclLyrSet
m_Snapper.ClearCache();

Basically, I'm getting poor snapping performance due to the presence of a basemap layer that contains multiple feature layers. If I turn that layer off (make invisible), the performance is good.

I've confirmed that all the layers (for composite type layers, I add each sub-layer to the exclusion as well) are being added to the exclusion set, but I can't seem to get the performance to improve without turning off that basemap layer. I'm not sure what I'm doing wrong - does the cache need to be cleared after each individual layer is excluded? I'd appreciate insights anyone might have regarding this. Thanks!

Mark C.
0 Kudos
8 Replies
by Anonymous User
Not applicable
Basemap layers are wrappers around the real layer. For each basemap layer that you want to put in the snapping exclusion set you'll need find and return the real layer and put that in, otherwise you wont notice any difference in snapping.

use IBasemapLayer.FindLayerWrapper to return IBasemapSubLayer then
IBasemapSubLayer.Layer to return the real layer.

In 10.1 we have included a UI option to exclude basemap layers from snapping.
0 Kudos
MarkCammarere
New Contributor III
Sean: Thanks for your prompt response, but I'm still having difficulty - now with the distinction between the basemap layer (the container), and the layers inside it. When you say "For each basemap layer that you want to put in the snapping exclusion set...", are you referring to the container, or the layers inside it? Here's some sample code that might illustrate my misunderstanding better (anExclLyrSet is of type ISet):

ILayer = aLyr = aMap.get_Layer(i);
if (aLyr.Name == "Basemap")
{
    IBasemapLayer aBmapLyr = (IBasemapLayer)aLyr;
    ICompositeLayer aCompLyr = (ICompositeLayer)aLyr;
    IBasemapSubLayer aBmapSubLyr = null;
    for (int j = 0; j < aCompLyr.Count; j++)
    {
        aLyr = aCompLyr.get_Layer(j);
        aBmapSubLyr = aBmapLyr.FindLayerWrapper(aLyr);
        if (aBmapSubLyr != null)
            anExclLyrSet.Add(aBmapSubLyr.Layer);
    }
}

When it gets to the aBmapSubLyr = aBmapLyr.FindLayerWrapper(aLyr); line, I get an error - probably because at this point aLyr is NOT a basemap layer (but one of the layers it contains). However, I'm not sure what else I could use as the ILayer argument of the FindLayerWrapper method?

Mark C.
0 Kudos
by Anonymous User
Not applicable
Mark,

FindLayerWrapper turns out to be the wrong way to do it....
You'll need to cast the basemap layer (the container) to a composite layer then get at the real layers through that.

The following code excludes all basemap layers from snapping.

    protected override void OnClick()
    {
      //Get the snap environment
      UID snapUID = new UID();
      snapUID.Value = "{E07B4C52-C894-4558-B8D4-D4050018D1DA}";
      m_SnappingEnv = ArcMap.Application.
        FindExtensionByCLSID(snapUID) as ISnappingEnvironment;
      m_Snapper = m_SnappingEnv.PointSnapper;

      ISet excludedLayerSet = new SetClass();
      m_Snapper.ExcludedLayers(ref excludedLayerSet);

      //loop through all layers in the map
      IMap map = ArcMap.Document.FocusMap;

      for (int i = 0; i < map.LayerCount; i++)
      {
        //is this a basemap layer?
        IBasemapLayer basemapLayer = map.get_Layer(i) as IBasemapLayer;
        if (basemapLayer != null)
        {
          ICompositeLayer basemapComposite = basemapLayer as ICompositeLayer;
          for (int j = 0; j < basemapComposite.Count; j++)
          {
            //get the real layer from the basemap/composite
            IBasemapSubLayer basemapSubLayer = basemapComposite.get_Layer(j) as IBasemapSubLayer;
            ILayer innerLayer = basemapSubLayer.Layer;
            excludedLayerSet.Add(innerLayer);
          }
        }
        m_Snapper.ClearCache();
      }
    }


Sorry about the confusion.
0 Kudos
MarkCammarere
New Contributor III
Thanks again, Sean! I'll try this code.

Mark C.
0 Kudos
AndersWallberg
New Contributor II
I am having problem to get ExcludedLayers to work in an ArcGIS Engine application. I have exact the same code as in your example.

This row returns true so it seems that my layer is excluded, but the i am getting snap feedback for all layers in my map.
bool layerIsExcluded = excludedLayerSet.Find(pLayer);

Any help is appriciated.

Anders
0 Kudos
by Anonymous User
Not applicable
Hey Anders,
What tool are you using to verify the result?
The sketch tool from editor toolset uses the classic snapping environment (IEngineSnapEnvironment) and wont recognize anything from IPointSnapper.ExcludedLayers. The measure tool will, or should, use the settings from the snapping toolset.
0 Kudos
AndersWallberg
New Contributor II
We have developed a custom tool  that inherits the BaseTool class with this OnMouseMove method.

public override void OnMouseMove(int Button, int Shift, int X, int Y)
        {
            IActiveView pActiveView = (IActiveView)m_pMapControl3.Map;
            m_pPoint = pActiveView.ScreenDisplay.DisplayTransformation.ToMapPoint(X, Y);

            ISnappingResult snapResult = m_SnappingEnvironment.PointSnapper.Snap(m_pPoint);

            //Feedback
            m_SnappingFeedback.Update(snapResult, 0);

            //Update the current location to move the cursor to the snapped location.
            if (snapResult != null)
                m_pPoint = snapResult.Location;
         }

And this is the code where we are trying to exclude layers from snapping. In this code we are trying to exclude ALL layers just for test.

public override void OnCreate(object hook)
{
//...other code

    UID guid = new UIDClass();
    guid.Value = "{E07B4C52-C894-4558-B8D4-D4050018D1DA}"; //Snapping extension.

    IExtension extension = extensionManager.FindExtension(guid);
    m_SnappingEnvironment = extension as ISnappingEnvironment;
    m_SnappingEnvironment.SnappingType = esriSnappingType.esriSnappingTypeVertex;

    m_SnappingFeedback = new SnappingFeedbackClass();
    m_SnappingFeedback.Initialize(hook, m_SnappingEnvironment, true);

    IPointSnapper pointSnapper = m_SnappingEnvironment.PointSnapper;

    ISet excludedLayerSet = new ESRI.ArcGIS.esriSystem.SetClass();

    pointSnapper.ExcludedLayers(ref excludedLayerSet);

    for (int i=0; i<m_pMapControl3.LayerCount; i++)
    {
        ILayer exkluderaLager = m_pMapControl3.Map.get_Layer(i);
        excludedLayerSet.Add(exkluderaLager); //Exkludera lagret
    }

    pointSnapper.ClearCache();
}


Everything except ExcludeLayers seems to work fine for us.

Anders
0 Kudos
by Anonymous User
Not applicable
Thanks for the sample code.

I tried setting excluded layers in a desktop add-in command, and engine command and an engine tool and they all worked for my scenario. I've attached the engine project, but its just using the same pattern so there shouldn't be anything odd there.

Maybe its something about the nature of the layers? whats their source? Do they have relationships, attachments, topologies etc?
Thanks.
0 Kudos