/// <summary> /// Perform some cleanup at the end of reading a shapefile. /// </summary> /// <param name="info">Shapefile read information.</param> private void EndReadShapeFile(ShapeFileReadInfo info) { if ( info != null && info.Stream != null ) { info.Stream.Close(); info.Stream.Dispose(); info.Stream = null; } this.EndReadShapeFile(); }
/// <summary> /// Read dBASE file attributes. /// </summary> /// <param name="info">Shapefile read information.</param> private void ReadDbaseAttributes(ShapeFileReadInfo info) { // Read attributes from the associated dBASE file. try { string dbaseFile = info.FileName.Replace(".shp", ".dbf"); dbaseFile = dbaseFile.Replace(".SHP", ".DBF"); info.ShapeFile.ReadAttributes(dbaseFile); } catch (OleDbException ex) { // Note: An exception will occur if the filename of the dBASE // file does not follow 8.3 naming conventions. In this case, // you must use its short (MS-DOS) filename. MessageBox.Show(ex.Message); // Activate the window. this.owner.Activate(); } }
/// <summary> /// Begin creating and displaying WPF shapes on the canvas. /// </summary> private void DisplayShapes(ShapeFileReadInfo info) { // Create shape brushes. if ( this.shapeBrushes == null ) this.CreateShapeBrushes(0.40, 45); // Set up the transformation for WPF shapes. if ( this.shapeTransform == null ) this.shapeTransform = this.CreateShapeTransform(info); // Schedule display of the first block of shapefile records // using the dispatcher. this.dispatcher.BeginInvoke(DispatcherPriority.Normal, new DisplayNextPrototype(this.DisplayNextShapeRecord), info); }
/// <summary> /// Display a block of shape records as WPF shapes, and schedule /// the next display with the dispatcher if needed. /// </summary> /// <param name="info">Shapefile read information.</param> private void DisplayNextShapeRecord(ShapeFileReadInfo info) { if ( this.cancelReadShapeFile ) return; // Create a block of WPF shapes and add them to the shape list. this.shapeList.Clear(); int index = info.RecordIndex; for( ; index < (info.RecordIndex + ShapeDisplay.displayShapesBlockingFactor); index++) { if ( index >= info.ShapeFile.Records.Count ) break; ShapeFileRecord record = info.ShapeFile.Records[index]; // Set the name of the WPF shape. ++this.wpfShapeCount; string shapeName = String.Format(System.Globalization.CultureInfo.InvariantCulture, "Shape{0}", this.wpfShapeCount); // Create the WPF shape. Shape shape; if ( record.NumberOfParts == 0 ) shape = this.CreateWPFPoint(shapeName, record); else shape = this.CreateWPFShape(shapeName, record); // Set a tooltip for the shape that displays up to 5 attribute values. shape.ToolTip = shape.Name; if ( record.Attributes != null ) { string attr = String.Empty; for (int i = 0; i < Math.Min(5, record.Attributes.ItemArray.GetLength(0)); i++) { attr += (", " + record.Attributes[i].ToString()); } shape.ToolTip += attr; } // Add the shape to the shape list. this.shapeList.Add(shape); // If the record just processed is very large, then don't process // any further records. if ( record.Points.Count > 5000 ) { ++index; break; } } // Set the record index to read next (as part of the // next dispatched task). info.RecordIndex = index; // Add the newly created WPF shapes to the canvas. foreach (Shape shape in this.shapeList) { this.canvas.Children.Add(shape); } this.shapeList.Clear(); // Display the current progress. double progressValue = (index * 100.0) / info.ShapeFile.Records.Count; progressValue = Math.Min(100, progressValue); this.ShowProgress("Creating WPF shapes...", progressValue); // See if we need to dispatch another display operation. if ( index < info.ShapeFile.Records.Count ) { // Schedule the next display at Background priority. this.dispatcher.BeginInvoke(DispatcherPriority.Background, new DisplayNextPrototype(this.DisplayNextShapeRecord), info); } else { // End the progress. this.ShowProgress("Creating WPF shapes...", 100); this.EndReadShapeFile(info); } }
/// <summary> /// Computes a transformation so that the shapefile geometry /// will maximize the available space on the canvas and be /// perfectly centered as well. /// </summary> /// <param name="info">Shapefile information.</param> /// <returns>A transformation object.</returns> private TransformGroup CreateShapeTransform(ShapeFileReadInfo info) { // Bounding box for the shapefile. double xmin = info.ShapeFile.FileHeader.XMin; double xmax = info.ShapeFile.FileHeader.XMax; double ymin = info.ShapeFile.FileHeader.YMin; double ymax = info.ShapeFile.FileHeader.YMax; // Width and height of the bounding box. double width = Math.Abs(xmax - xmin); double height = Math.Abs(ymax - ymin); // Aspect ratio of the bounding box. double aspectRatio = width / height; // Aspect ratio of the canvas. double canvasRatio = this.canvas.ActualWidth / this.canvas.ActualHeight; // Compute a scale factor so that the shapefile geometry // will maximize the space used on the canvas while still // maintaining its aspect ratio. double scaleFactor = 1.0; if ( aspectRatio < canvasRatio ) scaleFactor = this.canvas.ActualHeight / height; else scaleFactor = this.canvas.ActualWidth / width; // Compute the scale transformation. Note that we flip // the Y-values because the lon/lat grid is like a cartesian // coordinate system where Y-values increase upwards. ScaleTransform xformScale = new ScaleTransform(scaleFactor, -scaleFactor); // Compute the translate transformation so that the shapefile // geometry will be centered on the canvas. TranslateTransform xformTrans = new TranslateTransform(); xformTrans.X = (this.canvas.ActualWidth - (xmin + xmax) * scaleFactor) / 2; xformTrans.Y = (this.canvas.ActualHeight + (ymin + ymax) * scaleFactor) / 2; // Add the two transforms to a transform group. TransformGroup xformGroup = new TransformGroup(); xformGroup.Children.Add(xformScale); xformGroup.Children.Add(xformTrans); return xformGroup; }
/// <summary> /// Read shapes and attributes from the given shapefile. /// </summary> /// <param name="fileName">Full pathname of a shapefile.</param> public void ReadShapeFile(string fileName) { this.isReadingShapeFile = true; this.cancelReadShapeFile = false; // Create an object to store shapefile info during the read. ShapeFileReadInfo info = new ShapeFileReadInfo(); info.FileName = fileName; info.ShapeFile = new ShapeFile(); info.Stream = null; info.NumberOfBytesRead = 0; info.RecordIndex = 0; try { // Read the File Header first. info.Stream = new FileStream(fileName, FileMode.Open, FileAccess.Read); info.ShapeFile.ReadShapeFileHeader(info.Stream); info.NumberOfBytesRead = ShapeFileHeader.Length; // Schedule the first read of shape file records using the dispatcher. this.dispatcher.BeginInvoke(DispatcherPriority.Normal, new ReadNextPrototype(this.ReadNextShapeRecord), info); } catch (IOException ex) { this.EndReadShapeFile(info); MessageBox.Show(ex.Message); } }
/// <summary> /// Read a block of shape file records and possibly schedule /// the next read with the dispatcher. /// </summary> /// <param name="info">Shapefile read information.</param> private void ReadNextShapeRecord(ShapeFileReadInfo info) { if ( this.cancelReadShapeFile ) return; try { // Read a block of shape records. for (int i = 0; i < ShapeDisplay.readShapesBlockingFactor; i++) { ShapeFileRecord record = info.ShapeFile.ReadShapeFileRecord(info.Stream); info.NumberOfBytesRead += (4 + record.ContentLength) * 2; } } catch (FileFormatException ex) { this.EndReadShapeFile(info); MessageBox.Show(ex.Message); return; } catch (IOException) { // Display the end progress (100 percent). this.ShowProgress("Reading shapefile...", 100); // Read attributes from the associated dBASE file. this.ReadDbaseAttributes(info); // Display shapes on the canvas. if ( info.ShapeFile.Records.Count > 0 ) this.DisplayShapes(info); else this.EndReadShapeFile(info); return; } // Display the current progress. double progressValue = info.NumberOfBytesRead * 100.0 / (info.ShapeFile.FileHeader.FileLength * 2); progressValue = Math.Min(100, progressValue); this.ShowProgress("Reading shapefile...", progressValue); // Schedule the next read at Background priority. this.dispatcher.BeginInvoke(DispatcherPriority.Background, new ReadNextPrototype(this.ReadNextShapeRecord), info); }