public Layer readImpl(string filename) { // split filename in path and filename string[] split = filename.Split('\\'); string name = split.Last(); // remove extension name = name.Substring(0, name.Length - 4); string path = filename.Substring(0, filename.Length - name.Length - 4); layer = new Layer(name); // read .prj-file with same name or with name 'default.prj' string prjName = filename.Substring(0, filename.Length - 3) + "prj"; if (File.Exists(prjName)) layer.Projection = PrjReader.read(prjName); else if (File.Exists(path + "default.prj")) layer.Projection = PrjReader.read(path + "default.prj"); else { // warning message if missing prj file string msg = "No projection da found. Assuming " + SGIS.App.getSrsName(); MessageBox.Show(msg, "Missing spatial reference system: " + name, MessageBoxButtons.OK, MessageBoxIcon.Warning); } // try reading attribute file with same name string dbfName = filename.Substring(0, filename.Length - 3) + "dbf"; if (File.Exists(dbfName)) layer.DataTable = DbfReader.read(dbfName); // create stream from file FileStream f = File.Open(filename, FileMode.Open); br = new BinaryReaderExtension(f); pos = 0; length = (int)br.BaseStream.Length; readHeader(); // set bounding box from values in header layer.Boundingbox = new Envelope(minx, maxx, miny, maxy); layer.createQuadTree(); // content starts at pos 100 pos = 100; // read all shapes until end while (pos < length) readShape(); br.Close(); // features now converted to application srs layer.Projection = SGIS.App.SRS; return layer; }
// copy selected feature to new layer private void toLayerButton_Click(object sender, EventArgs e) { toolBuilder.addHeader("Export selection"); // textbox for new layer name TextBox textbox = toolBuilder.addTextboxWithCaption("Layer name:"); Label errorLabel = toolBuilder.addErrorLabel(); // button for performing copy Button selectButton = toolBuilder.addButton("Copy selection", (Layer l) => { if (textbox.Text.Length == 0) { errorLabel.Text = "Provide a name"; return; } Layer newl = new Layer(textbox.Text); // copy attributes newl.DataTable = l.DataTable; // copy features foreach (Feature f in l.Selected) newl.addFeature(new Feature((Geometry)f.Geometry.Clone(), f.ID)); newl.calculateBoundingBox(); newl.createQuadTree(); Layers.Insert(0, newl); // select newly made layer layerList.SelectedItem = newl; }); // change default new layer name when new layer is selected toolBuilder.resetAction = (Layer l) => { textbox.Text = (l == null) ? "" : l.Name + "_copy"; }; toolBuilder.reset(); }
// 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(); }
// buffer layer private void bufferButton_Click(object sender, EventArgs e) { toolBuilder.addHeader("Buffer"); // textbox for buffer distance TextBox distBox = toolBuilder.addTextboxWithCaption("Distance (m):"); // textbox for new layername TextBox nameBox = toolBuilder.addTextboxWithCaption("New layername:"); // label for errors Label errorLabel = toolBuilder.addErrorLabel(); // button for performing buffer Button selectButton = toolBuilder.addButton("Buffer", (Layer l) => { double dist = 0; // buffer does not work on lat-long projections if (SRS.IsLatLong) { toolBuilder.setError("Incompatible SRS"); return; } // distance must be a number if (!double.TryParse(distBox.Text, out dist)) { toolBuilder.setError("Not a number"); return; } // user must give new layer name if (nameBox.Text.Length == 0) { toolBuilder.setError("Provide a name"); return; } // create new layer Layer newl = new Layer(nameBox.Text); newl.DataTable = l.DataTable; List<Feature> flist = l.Features.Values.ToList(); // initialise progress bar progressLabel.Text = "Buffering"; progressBar.Minimum = 0; progressBar.Maximum = flist.Count; // threadsafe list of new features ConcurrentBag<Feature> newFeatures = new ConcurrentBag<Feature>(); BackgroundWorker bw = new BackgroundWorker(); bw.WorkerReportsProgress = true; // perform buffering in other thread bw.DoWork += (object wsender, DoWorkEventArgs we) => { using (var finished = new CountdownEvent(1)) { // for each feature for (int i = 0; i < flist.Count; i++) { // add the task to buffer a feature to a thread pool finished.AddCount(); Feature capture = flist[i]; ThreadPool.QueueUserWorkItem((state) => { // get feature Feature f = capture; // add buffered feature newFeatures.Add(new Feature(f.Geometry.Buffer(dist), f.ID)); bw.ReportProgress(i); finished.Signal(); }, null); } finished.Signal(); finished.Wait(); } bw.ReportProgress(-1); // add all buffered features to layer foreach(Feature f in newFeatures) { newl.addFeature(f); bw.ReportProgress(1); } newl.calculateBoundingBox(); newl.createQuadTree(); }; bw.RunWorkerCompleted += (object wsender, RunWorkerCompletedEventArgs we) => { // reset progress bar progressBar.Value = 0; progressLabel.Text = ""; // add and zoom newly made layer Layers.Insert(0, newl); layerList.SelectedItem = newl; }; bw.ProgressChanged += (object wsender, ProgressChangedEventArgs we) => { // update progress bar and progress label if (we.ProgressPercentage == -1){ progressBar.Value = 0; progressLabel.Text = "Creating spatial index"; } else progressBar.Value += 1; }; bw.RunWorkerAsync(); }); toolBuilder.resetAction = (Layer l) => { if (SRS.IsLatLong) toolBuilder.setError("Incompatible SRS"); nameBox.Text = (l == null) ? "" : l.Name + "_buffer"; }; toolBuilder.reset(); }
// merge two layers private void mergeButton_Click(object sender, EventArgs e) { toolBuilder.addHeader("Merge"); // dropdown for selecting second layer ComboBox layerSelect = toolBuilder.addLayerSelect("Merge with:"); // textbox for new layername TextBox textbox = toolBuilder.addTextboxWithCaption("New layername:"); Label errorLabel = toolBuilder.addErrorLabel(); // button for performing merge Button button = toolBuilder.addButton("Merge", (Layer l) => { // no new layer name given if (textbox.Text.Length == 0) { toolBuilder.setError("Provide name"); return; } Layer unionLayer = (Layer) layerSelect.SelectedItem; // layers must have same shapetype if (l.shapetype != unionLayer.shapetype) { toolBuilder.setError("Incompatible types"); return; } // create new layer Layer newLayer = new Layer(textbox.Text); // create boundingbox as combination of two bb's newLayer.Boundingbox = new Envelope(l.Boundingbox); newLayer.Boundingbox.ExpandToInclude(unionLayer.Boundingbox); newLayer.createQuadTree(); // add all features from one layer foreach (Feature f in l.Features.Values) newLayer.addFeature(new Feature((IGeometry)f.Geometry.Clone())); // add all features from other layer foreach (Feature f in unionLayer.Features.Values) newLayer.addFeature(new Feature((IGeometry)f.Geometry.Clone())); // insert newly made layer Layers.Insert(0, newLayer); // redraw map redraw(); }); // change default new layer name when selected layer changes toolBuilder.resetAction = (Layer l) => { textbox.Text = (l == null) ? "" : l.Name + "_merge"; }; toolBuilder.reset(); }
// calculate intersection of layers private void intersectButton_Click(object sender, EventArgs e) { toolBuilder.addHeader("Intersect"); // dropdown for selecting other layer ComboBox layerSelect = toolBuilder.addLayerSelect("Intersect with:"); // textbox for new layer name TextBox textbox = toolBuilder.addTextboxWithCaption("New layername:"); // laber for errors Label errorLabel = toolBuilder.addErrorLabel(); //button for performing intersection Button button = toolBuilder.addButton("Intersect", (Layer l) => { // new layer name not given if (textbox.Text.Length == 0) { toolBuilder.setError("Provide name"); return; } Layer intersectLayer = (Layer)layerSelect.SelectedItem; Layer newLayer = new Layer(textbox.Text); // if both layers have attributes if (l.DataTable != null && intersectLayer.DataTable != null) { // merge attributes, columnName collisions may be overwritten DataTable a = l.DataTable.Clone(); newLayer.DataTable = intersectLayer.DataTable.Clone(); newLayer.DataTable.Merge(a, true, MissingSchemaAction.Add); } // if only one layer has attributes else if (l.DataTable != null && intersectLayer.DataTable == null) { newLayer.DataTable = l.DataTable.Clone(); } // if only the other layer has attributes else if (l.DataTable == null && intersectLayer.DataTable != null) { newLayer.DataTable = intersectLayer.DataTable.Clone(); } // init progress bar progressLabel.Text = "Intersection"; progressBar.Minimum = 0; progressBar.Maximum = l.Features.Values.Count; // background worker for running in another thread BackgroundWorker bw = new BackgroundWorker(); bw.WorkerReportsProgress = true; bw.DoWork += (object wsender, DoWorkEventArgs we) => { // loop through all features for (int i = 0; i < l.Features.Count; i++ ) { Feature f = l.Features.Values.ElementAt(i); bw.ReportProgress(i); // get intersecting features var intersections = intersectLayer.getWithin(f.Geometry); foreach (Feature intersect in intersections) { DataRow arow = l.getRow(f); DataRow brow = intersectLayer.getRow(intersect); // calculate intersection Feature result = new Feature(f.Geometry.Intersection(intersect.Geometry)); int id = newLayer.addFeature(result); // merge attributes if (newLayer.DataTable != null) { DataRow dr = newLayer.DataTable.NewRow(); if (arow != null) foreach (DataColumn dc in arow.Table.Columns) dr[dc.ColumnName] = arow[dc.ColumnName]; if (brow != null) foreach (DataColumn dc in brow.Table.Columns) dr[dc.ColumnName] = brow[dc.ColumnName]; dr["sgis_id"] = id; newLayer.DataTable.Rows.Add(dr); } } } }; bw.RunWorkerCompleted += (object wsender, RunWorkerCompletedEventArgs we) => { // reset progress bar progressBar.Value = 0; progressLabel.Text = ""; // finalise new layer newLayer.calculateBoundingBox(); newLayer.createQuadTree(); Layers.Insert(0, newLayer); redraw(); }; bw.ProgressChanged += (object wsender, ProgressChangedEventArgs we) => { // update progress bar progressBar.Value = we.ProgressPercentage; }; bw.RunWorkerAsync(); }); // reset new layer name toolBuilder.resetAction += (Layer l) => { textbox.Text = (l == null) ? "" : l.Name + "_intersect"; }; toolBuilder.reset(); }
private void diffButton_Click(object sender, EventArgs e) { toolBuilder.addHeader("Difference"); // dropdown for selecting other layer ComboBox layerSelect = toolBuilder.addLayerSelect("Layer to subtract:"); // textbox for new layer name TextBox textbox = toolBuilder.addTextboxWithCaption("New layername:"); // label for errors Label errorLabel = toolBuilder.addErrorLabel(); // button for performing subtraction Button button = toolBuilder.addButton("Subtract", (Layer l) => { // no new layer name is given if (textbox.Text.Length == 0) { toolBuilder.setError("Provide name"); return; } // layers must have the same type of shapes Layer unionLayer = (Layer)layerSelect.SelectedItem; if (l.shapetype != unionLayer.shapetype) { toolBuilder.setError("Incompatible types"); return; } Layer newLayer = new Layer(textbox.Text); newLayer.DataTable = l.DataTable; // init progress bar progressLabel.Text = "Subtracting"; progressBar.Minimum = 0; progressBar.Maximum = l.Features.Values.Count; // background worker for running operation in another thread BackgroundWorker bw = new BackgroundWorker(); bw.WorkerReportsProgress = true; bw.DoWork += (object wsender, DoWorkEventArgs we) => { // threadsafe list for storing new features ConcurrentBag<Feature> newFeatures = new ConcurrentBag<Feature>(); using (var finished = new CountdownEvent(1)) { foreach (Feature f in l.Features.Values) { finished.AddCount(); Feature capt = f; // in each thread ThreadPool.QueueUserWorkItem((state) => { // clone feature Feature newf = new Feature((IGeometry)capt.Geometry.Clone(), capt.ID); // get intersecting features var intersects = unionLayer.getWithin(capt.Geometry); // subtract intersecting features foreach (Feature intersect in intersects) newf.Geometry = newf.Geometry.Difference(intersect.Geometry); // if there is something left of the original feature if (!newf.Geometry.IsEmpty) // add it to new feature list newFeatures.Add(newf); bw.ReportProgress(1); finished.Signal(); }, null); } finished.Signal(); finished.Wait(); } bw.ReportProgress(-newFeatures.Count); // add all processed features to new layer foreach (Feature f in newFeatures) { newLayer.addFeature(f); bw.ReportProgress(1); } }; bw.RunWorkerCompleted += (object wsender, RunWorkerCompletedEventArgs we) => { // reset progressbar progressBar.Value = 0; progressLabel.Text = ""; // create quad tree and insert new layer newLayer.calculateBoundingBox(); newLayer.createQuadTree(); 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 = "Creating spatial index"; } else progressBar.Value += we.ProgressPercentage; }; bw.RunWorkerAsync(); }); // reset new layer name when selected layer changes toolBuilder.resetAction += (Layer l) => { textbox.Text = (l == null) ? "" : l.Name + "_diff"; }; toolBuilder.reset(); }