ThinkGeo.com    |     Documentation    |     Premium Support

CustomOverlay

I am using CustomOverlays now and I have a question or two.  First, the project setup.  I have four custom overlays, "Images", "Landbase", "CustomerData", and "Highlight".  Only Landbase and CustomerData contain editable features, so these are the ones used with this process.


I am trying to add the ability to click on the map and edit the nearest feature and or feature record.  I may be going about this all wrong, but it seems to work.  The basic process is the user presses a tool bar button named "Edit Feature" and then click on the map.  The user doesn't have to specify the feature type, table, or anything else.


At this point I intercept the map click and create a bounding box.  I search all of the editable layers and add features within the bounding box to a collection.  I then highlight the first feature and wait for the user to tell me if this is the correct feature to edit.  The user does this by clicking the right mouse button to highlight the next feature or the left mouse button to accept the highlighted feature.


The process would be simpler if I could limit the choices, but I can't.  If only one feature is near the pick point I imediately go into edit mode withour highlighting anything.  I have a global variable that tracks the current selected feature.  The following code adds the features to the collection:


 



private void LoadFeaturesInRange(double iX, double iY)
{
    foreach (Overlay currentOverlay in winformsMap1.CustomOverlays)
    {
        if (currentOverlay is LayerOverlay)
        {
            LayerOverlay myOverlay = (LayerOverlay)currentOverlay;
            foreach (Layer curLayer in myOverlay.Layers)
            {
                if (curLayer is FeatureLayer)
                {
                    curLayer.Open();
                    double range = winformsMap1.CurrentExtent.Width / 100;
                    if (range < winformsMap1.CurrentExtent.Height / 100)
                    {
                        range = winformsMap1.CurrentExtent.Height / 100;
                    }
                    FeatureLayer myLayer = (FeatureLayer)curLayer;
                    Collection<Feature> selFeats = myLayer.QueryTools.GetFeaturesInsideBoundingBox(new RectangleShape(iX - range, iY + range, iX + range, iY - range), ReturningColumnsType.AllColumns);
                    foreach (Feature curFeature in selFeats)
                    {
                        selectedFeatures.Add(curFeature);
                        selectedTables.Add(myLayer.Name);
                    }
                }
            }
        }
     }
     if (selectedFeatures.Count > 0) selCounter = 1;
}

 


This code gets the current feature for editing:


 



private FeatureLayer GetCurrentFeatureDefinition(ref Collection<FeatureSourceColumn> oColumns, ref Feature oFeature)
{
    IEnumerator<Feature> selFeatures = selectedFeatures.GetEnumerator();
    IEnumerator<string> selTables = selectedTables.GetEnumerator();
    selFeatures.MoveNext();
    selTables.MoveNext();
    for (int Looper = 1; Looper < selCounter; Looper++)
    {
        selFeatures.MoveNext();
        selTables.MoveNext();
    }
    oFeature = selFeatures.Current;
    //This is for CustomOverlays
    FeatureLayer currentLayer = null;
    LayerOverlay curOverlay = (LayerOverlay)winformsMap1.CustomOverlays["DataOverlay"];
    if (curOverlay.Layers.Contains(selTables.Current) == true)
    {
        currentLayer = (FeatureLayer)curOverlay.Layers[selTables.Current];
    }
    else
    {
        curOverlay = (LayerOverlay)winformsMap1.CustomOverlays["LandbaseOverlay"];
        currentLayer = (FeatureLayer)curOverlay.Layers[selTables.Current];
    }
    //This is for Static/Dynamic Overlays
    //FeatureLayer currentLayer = winformsMap1.FindFeatureLayer(selTables.Current);
    oColumns = currentLayer.QueryTools.GetColumns();
    return currentLayer;
}

 


Am I going about this correctly?  Is there an easier way?

When using Dynamic and Static Overlays I can use RefreshDynamic.  Is there a way to refresh a single custom overlay or do I have to refresh everything?  Finally, What is the AdornmentOverlay?


 



Charles,


Here are some notes on your questions and codes.


1, maybe you can merge “Landbase” and “CustomerData” to one overlay, They are all layerOverlay so it’s possible, they all have edit features so it is meaningful. In that way, you do not need to check other overlays and codes can be much easier.


2, the editable Features are cached using selectedFeature and selectedTables, it might be a problem that the 2 objects have to be synchronized explicitly. Maybe it’s better to create a little struct to record every feature, so we only need to maintain one cache object instead of two. One thing I am not sure is why using the low level APIs like GetEnumerator(), I think selectedFeature is a collection(as it has the API Add()) so you can use some more advanced feature, like index, which is easier to use.  Also I found feature itself is cached, we can cache the layer name and feature id, and retrieve the feature back through that id. That will save some memory but takes a bit more time when retrieving the data, so just an option.


3, In the coming version (will be available tomorrow), we correct the method winformsMap1.FindFeatureLayer and it will work with CustomOverlays. So use this API and your codes will be easier.


Here I tried to rewrite the code with the above changes. As I didn't know all your codes, it may have some problems and please feel free to change. 



        private void LoadFeaturesInRange(double iX, double iY)
        {
            LayerOverlay myOverlay = winformsMap1.CustomOverlays["EditOverlay"];
            foreach (Layer curLayer in myOverlay.Layers)
            {
                if (curLayer is FeatureLayer)
                {
                    double range = winformsMap1.CurrentExtent.Width / 100;
                    if (range < winformsMap1.CurrentExtent.Height / 100)
                    {
                        range = winformsMap1.CurrentExtent.Height / 100;
                    }
                    FeatureLayer myLayer = (FeatureLayer)curLayer;
                    myLayer.Open();
                    Collection<Feature> selFeats = myLayer.QueryTools.GetFeaturesInsideBoundingBox(new RectangleShape(iX - range, iY + range, iX + range, iY - range), ReturningColumnsType.AllColumns);
                    myLayer.Close();
                    foreach (Feature curFeature in selFeats)
                    {
                        selectedFeatures.Add(new CachedInfo(curFeature, myLayer.Name));
                    }
                }
            }
            if (selectedFeatures.Count > 0) selCounter = 1;
        }

        private FeatureLayer GetCurrentFeatureDefinition(ref Collection<FeatureSourceColumn> oColumns, ref Feature oFeature)
        {
            oFeature = selectedFeatures[selCounter].Feature;

            //This is for CustomOverlays
            FeatureLayer currentLayer = winformsMap1.FindFeatureLayer(selectedFeatures[selCounter].LayerName);
            oColumns = currentLayer.QueryTools.GetColumns();
            return currentLayer;
        }

......
 class CachedInfo
    {
        public CachedInfo(Feature feature, string layerName)
        {
            this.Feature = feature;
            this.LayerName = layerName;
        }
        public Feature Feature
        { get; set; }
        public string LayerName
        { get; set; }
    }


4, For now, there is no way to refresh just a single custom overlay and you need to refresh everything. We will enhance that.


5, AdornmentOverlay is for displaying some static information on top of the map like titles, logos, scalebar or even compact.  You can see a little instruction here (and click the link “Adornment Layers”) or see the sample in “Moving around the Map->CreateAScaleLineAdornmentLayer”


Thanks,


Ben