Beispiel #1
0
        // perform union on currently selected layer
        private void unionButton_Click(object sender, EventArgs e)
        {
            toolBuilder.addHeader("Union");
            // textbox for new layername
            TextBox textbox = toolBuilder.addTextboxWithCaption("New layername:");
            Label errorLabel = toolBuilder.addErrorLabel();
            Button button = toolBuilder.addButton("Union", (Layer l) =>
            {
                // user has not set new layername
                if (textbox.Text.Length == 0)
                {
                    toolBuilder.setError("Provide name");
                    return;
                }
                // create temporary layer
                Layer copyLayer = new Layer(l.Name);
                copyLayer.Boundingbox = new Envelope(l.Boundingbox);
                copyLayer.createQuadTree();

                // copy all features to temp layer
                foreach (Feature f in l.Features.Values)
                    copyLayer.addFeature(new Feature((IGeometry)f.Geometry.Clone(), f.ID));

                // create new layer with same boundingbox
                Layer newLayer = new Layer(textbox.Text);
                newLayer.Boundingbox = new Envelope(l.Boundingbox);
                newLayer.createQuadTree();

                // init progress bar
                int numFeatures = copyLayer.Features.Values.Count;
                progressLabel.Text = "Performing union";
                progressBar.Minimum = 0;
                progressBar.Maximum = numFeatures;

                BackgroundWorker bw = new BackgroundWorker();
                bw.WorkerReportsProgress = true;
                // perform merge in another thread
                bw.DoWork += (object wsender, DoWorkEventArgs we) =>
                {
                    // threadsafe list of merged features
                    ConcurrentBag<Feature> newFeatures = new ConcurrentBag<Feature>();
                    var finished = new CountdownEvent(1);
                    Object _lock = new object();
                    // create thread function
                    var merge = new WaitCallback((state) =>
                    {
                        Random rnd = new Random();
                        while (true)
                        {
                            Feature f;
                            lock (_lock)
                            {
                                // break if no more features
                                if (copyLayer.Features.Count == 0)
                                    break;
                                // get random index
                                int index = rnd.Next(copyLayer.Features.Count);
                                // get corresponding random feature
                                f = copyLayer.Features[copyLayer.Features.Keys.ToList()[index]];
                                // remove feature from layer
                                copyLayer.delFeature(f);
                            }
                            f.ID = -1;
                            while (true)
                            {
                                List<Feature> intersects;
                                // aquire lock to avoid race conditions
                                lock (_lock)
                                {
                                    // get all features intersecting feature
                                    intersects = copyLayer.getWithin(f.Geometry);
                                    // remove features from layer
                                    foreach (Feature intersect in intersects)
                                        copyLayer.delFeature(intersect);
                                }
                                // if no intersects, no merging is necessary
                                if (intersects.Count == 0)
                                    break;
                                // merge all features
                                foreach (Feature intersect in intersects)
                                {
                                    f = new Feature(f.Geometry.Union(intersect.Geometry));
                                    bw.ReportProgress(1);
                                }
                            }
                            // add feature to list of new features
                            newFeatures.Add(f);
                        }
                        finished.Signal();
                    });
                    // spawn eight threads, this is not always optimal but a good approximation
                    for (int i = 0; i < 8; i++)
                    {
                        finished.AddCount();
                        ThreadPool.QueueUserWorkItem(merge);
                    }
                    finished.Signal();
                    finished.Wait();

                    bw.ReportProgress(-newFeatures.Count);
                    // add all merged features back to temp layer
                    foreach (Feature f in newFeatures)
                        copyLayer.addFeature(f);
                    newFeatures = new ConcurrentBag<Feature>();
                    finished = new CountdownEvent(1);
                    // perform a final single threaded merge
                    merge(false);

                    // add all final merged features to new layer
                    foreach (Feature f in newFeatures)
                        newLayer.addFeature(f);
                };
                bw.RunWorkerCompleted += (object wsender, RunWorkerCompletedEventArgs we) =>
                {
                    // reset progress bar
                    progressBar.Value = 0;
                    progressLabel.Text = "";

                    // insert new layer and redraw map
                    Layers.Insert(0, newLayer);
                    redraw();
                };
                bw.ProgressChanged += (object wsender, ProgressChangedEventArgs we) =>
                {
                    //  update progress bar
                    if (we.ProgressPercentage < 0)
                    {
                        progressBar.Value = 0;
                        progressBar.Maximum = -we.ProgressPercentage;
                        progressLabel.Text = "Union - Second pass";
                    }
                    else
                        progressBar.Value += we.ProgressPercentage;
                };
                bw.RunWorkerAsync();
            });
            // reset default new layer name when selected layer is changed
            toolBuilder.resetAction = (Layer l) => {
                textbox.Text = (l == null) ? "" : l.Name + "_union";
            };
            toolBuilder.reset();
        }