/// <summary> /// If no file exists, this writes the header and no-data values. If a file exists, it will assume /// that data already has been filled in the file and will attempt to insert the data values /// as a window into the file. If you want to create a copy of the file and values, just use /// System.IO.File.Copy, it almost certainly would be much more optimized. /// </summary> /// <param name="filename">The string filename to write values to.</param> public void Write(string filename) { FileStream fs; BinaryWriter bw; ProgressMeter pm = new ProgressMeter(ProgressHandler, "Writing values to " + filename, NumRows); long expectedByteCount = NumRows*NumColumns*ByteSize; if (expectedByteCount < 1000000) pm.StepPercent = 5; if (expectedByteCount < 5000000) pm.StepPercent = 10; if (expectedByteCount < 100000) pm.StepPercent = 50; if (File.Exists(filename)) { FileInfo fi = new FileInfo(filename); // if the following test fails, then the target raster doesn't fit the bill for pasting into, so clear it and write a new one. if (fi.Length == HeaderSize + ByteSize*NumColumnsInFile*NumRowsInFile) { WriteHeader(filename); // assume that we already have a file set up for us, and just write the window of values into the appropriate place. fs = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, ByteSize*NumColumns); fs.Seek(HeaderSize, SeekOrigin.Begin); fs.Seek(ByteSize*StartRow, SeekOrigin.Current); bw = new BinaryWriter(fs); // encoding doesn't matter because we don't have characters for (int row = 0; row < NumRows; row++) { fs.Seek(StartColumn*ByteSize, SeekOrigin.Current); for (int col = 0; col < NumColumns; col++) { // this is the only line that is type dependant, but I don't want to type check on every value bw.Write(Data[row][col]); } fs.Flush(); // Since I am buffering, make sure that I write the buffered data before seeking fs.Seek((NumColumnsInFile - EndColumn - 1)*ByteSize, SeekOrigin.Current); pm.CurrentValue = row; } pm.Reset(); bw.Close(); return; } } if (File.Exists(filename)) File.Delete(filename); WriteHeader(filename); // Open as append and it will automatically skip the header for us. fs = new FileStream(filename, FileMode.Append, FileAccess.Write, FileShare.None, ByteSize*NumColumnsInFile); bw = new BinaryWriter(fs); // the row and column counters here are relative to the whole file, not just the window that is currently in memory. pm.EndValue = NumRowsInFile; for (int row = 0; row < NumRowsInFile; row++) { for (int col = 0; col < NumColumnsInFile; col++) { if (row < StartRow || row > EndRow || col < StartColumn || col > EndColumn) bw.Write(DoubleNoDataValue); else bw.Write(Data[row - StartRow][col - StartColumn]); } pm.CurrentValue = row; } fs.Flush(); // flush anything that hasn't gotten written yet. pm.Reset(); bw.Close(); }
/// <summary> /// /// </summary> /// <param name="filename"></param> /// <returns></returns> private IImageData OpenFile(string filename) { GdalImage result = new GdalImage(filename); if(result.Width > 8000 || result.Height > 8000) { // Firstly, if there are pyramids inside of the GDAL file itself, we can just work with this directly, // without creating our own pyramid image. // For now, we can't get fast, low-res versions without some kind of pyramiding happening. // since that can take a while for huge images, I'd rather do this once, and create a kind of // standardized file-based pyramid system. Maybe in future pyramid tiffs could be used instead? string pyrFile = Path.ChangeExtension(filename, ".mwi"); if(File.Exists(pyrFile)) { if(File.Exists(Path.ChangeExtension(pyrFile, ".mwh"))) { return new PyramidImage(filename); } File.Delete(pyrFile); } GdalImageSource gs = new GdalImageSource(filename); PyramidImage py = new PyramidImage(pyrFile, gs.Bounds); int width = gs.Bounds.NumColumns; int blockHeight = 64000000 / width; if (blockHeight > gs.Bounds.NumRows) blockHeight = gs.Bounds.NumRows; int numBlocks = (int)Math.Ceiling(gs.Bounds.NumRows/(double)blockHeight); ProgressMeter pm = new ProgressMeter(ProgressHandler, "Copying Data To Pyramids", numBlocks* 2); ProgressHandler.Progress("pyramid", 0, "Copying Data To Pyramids: 0% Complete"); Application.DoEvents(); for(int j = 0; j < numBlocks; j++) { int h = blockHeight; if(j==numBlocks-1) { h = gs.Bounds.NumRows - j*blockHeight; } Stopwatch sw = new Stopwatch(); sw.Start(); byte[] vals = gs.ReadWindow(j*blockHeight, 0, h, width, 0); Debug.WriteLine("Reading Value time: " + sw.ElapsedMilliseconds); pm.CurrentValue = j * 2 + 1; sw.Reset(); sw.Start(); py.WriteWindow(vals, j * blockHeight, 0, h, width, 0); sw.Stop(); Debug.WriteLine("Writing Pyramid time: " + sw.ElapsedMilliseconds); pm.CurrentValue = (j+1) * 2; } gs.Dispose(); pm.Reset(); py.CreatePyramids(ProgressHandler); py.WriteHeader(pyrFile); return py; } result.Open(filename); return result; }
/// <summary> /// This assumes that the base image has been written to the file. This will now attempt to calculate /// the down-sampled images. /// </summary> /// <param name="progressHandler"></param> public void CreatePyramids(IProgressHandler progressHandler) { int w = _header.ImageHeaders[0].NumColumns; int h = _header.ImageHeaders[0].NumRows; int blockHeight = 32000000/w; if (blockHeight > h) blockHeight = h; int numBlocks = (int)Math.Ceiling(h/(double)blockHeight); ProgressMeter pm = new ProgressMeter(progressHandler, "Generating Pyramids", _header.ImageHeaders.Length * numBlocks); for(int block = 0; block < numBlocks; block++) { GC.Collect(); // Normally block height except for the lowest block which is usually smaller int bh = blockHeight; if(block == numBlocks -1) bh = h - block*blockHeight; // Read a block of bytes into a bitmap byte[] vals = ReadWindow(block * blockHeight, 0, bh, w, 0); Bitmap bmp = new Bitmap(w, bh); BitmapData bd = bmp.LockBits(new Rectangle(0, 0, w, bh), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); Marshal.Copy(vals, 0, bd.Scan0, vals.Length); bmp.UnlockBits(bd); // cycle through the scales, and write the resulting smaller bitmap in an appropriate spot int sw = w; // scale width int sh = bh; // scale height int sbh = blockHeight; for (int scale = 1; scale < _header.ImageHeaders.Length - 1; scale++) { sw = sw / 2; sh = sh / 2; sbh = sbh / 2; if(sh == 0 || sw == 0) { break; } Bitmap subSet = new Bitmap(sw, sh); Graphics g = Graphics.FromImage(subSet); g.DrawImage(bmp, 0, 0, sw, sh); bmp.Dispose(); // since we keep getting smaller, don't bother keeping the big image in memory any more. bmp = subSet; // keep the most recent image alive for making even smaller subsets. g.Dispose(); BitmapData bdata = bmp.LockBits(new Rectangle(0, 0, sw, sh), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); byte[] res = new byte[sw * sh * 4]; Marshal.Copy(bdata.Scan0, res, 0, res.Length); bmp.UnlockBits(bdata); WriteWindow(res, sbh * block, 0, sh, sw, scale); pm.CurrentValue = block*_header.ImageHeaders.Length + scale; } bmp.Dispose(); } pm.Reset(); }
// X Y Poly Lines: Total Length = 28 Bytes // --------------------------------------------------------- // Position Value Type Number Byte Order // --------------------------------------------------------- // Byte 0 Record Number Integer 1 Big // Byte 4 Content Length Integer 1 Big // Byte 8 Shape Type 3 Integer 1 Little // Byte 12 Xmin Double 1 Little // Byte 20 Ymin Double 1 Little // Byte 28 Xmax Double 1 Little // Byte 36 Ymax Double 1 Little // Byte 44 NumParts Integer 1 Little // Byte 48 NumPoints Integer 1 Little // Byte 52 Parts Integer NumParts Little // Byte X Points Point NumPoints Little // X Y M Poly Lines: Total Length = 34 Bytes // --------------------------------------------------------- // Position Value Type Number Byte Order // --------------------------------------------------------- // Byte 0 Record Number Integer 1 Big // Byte 4 Content Length Integer 1 Big // Byte 8 Shape Type 23 Integer 1 Little // Byte 12 Box Double 4 Little // Byte 44 NumParts Integer 1 Little // Byte 48 NumPoints Integer 1 Little // Byte 52 Parts Integer NumParts Little // Byte X Points Point NumPoints Little // Byte Y* Mmin Double 1 Little // Byte Y + 8* Mmax Double 1 Little // Byte Y + 16* Marray Double NumPoints Little // X Y Z M Poly Lines: Total Length = 44 Bytes // --------------------------------------------------------- // Position Value Type Number Byte Order // --------------------------------------------------------- // Byte 0 Record Number Integer 1 Big // Byte 4 Content Length Integer 1 Big // Byte 8 Shape Type 13 Integer 1 Little // Byte 12 Box Double 4 Little // Byte 44 NumParts Integer 1 Little // Byte 48 NumPoints Integer 1 Little // Byte 52 Parts Integer NumParts Little // Byte X Points Point NumPoints Little // Byte Y Zmin Double 1 Little // Byte Y + 8 Zmax Double 1 Little // Byte Y + 16 Zarray Double NumPoints Little // Byte Z* Mmin Double 1 Little // Byte Z+8* Mmax Double 1 Little // Byte Z+16* Marray Double NumPoints Little private void FillPolygons(string filename, IProgressHandler progressHandler) { // Check to ensure the filename is not null if (filename == null) { throw new NullReferenceException(MessageStrings.ArgumentNull_S.Replace("%S", filename)); } if (File.Exists(filename) == false) { throw new FileNotFoundException(MessageStrings.FileNotFound_S.Replace("%S", filename)); } // Get the basic header information. ShapefileHeader header = new ShapefileHeader(filename); Extent = new Extent(new[]{header.Xmin, header.Ymin, header.Xmax, header.Ymax}); // Check to ensure that the filename is the correct shape type if (header.ShapeType != ShapeTypes.Polygon && header.ShapeType != ShapeTypes.PolygonM && header.ShapeType != ShapeTypes.PolygonZ) { throw new ArgumentException(MessageStrings.FileNotLines_S.Replace("%S", filename)); } // Reading the headers gives us an easier way to track the number of shapes and their overall length etc. List<ShapeHeader> shapeHeaders = ReadIndexFile(filename); // This will set up a reader so that we can read values in huge chunks, which is much faster than one value at a time. IO.BufferedBinaryReader bbReader = new IO.BufferedBinaryReader(filename, progressHandler); if (bbReader.FileLength == 100) { // The shapefile is empty so we can simply return here bbReader.Close(); return; } // Skip the shapefile header by skipping the first 100 bytes in the shapefile bbReader.Seek(100, SeekOrigin.Begin); int numShapes = shapeHeaders.Count; int [] partOffsets = new int[numShapes]; byte[] bigEndians = new byte[numShapes * 8]; byte[] allBounds = new byte[numShapes * 32]; ByteBlock allParts = new ByteBlock(BLOCKSIZE); // probably all will be in one block, but use a byteBlock just in case. ByteBlock allCoords = new ByteBlock(BLOCKSIZE); bool isM = (header.ShapeType == ShapeTypes.PolyLineM || header.ShapeType == ShapeTypes.PolyLineZ); bool isZ = (header.ShapeType == ShapeTypes.PolyLineZ); ByteBlock allZ = null; ByteBlock allM = null; if (isZ) { allZ = new ByteBlock(BLOCKSIZE); } if (isM) { allM = new ByteBlock(BLOCKSIZE); } int pointOffset = 0; for (int shp = 0; shp < numShapes; shp++) { // Read from the index file because some deleted records // might still exist in the .shp file. long offset = (shapeHeaders[shp].ByteOffset); bbReader.Seek(offset, SeekOrigin.Begin); // Position Value Type Number Byte Order ShapeRange shape = new ShapeRange(FeatureTypes.Polygon); //-------------------------------------------------------------------- shape.RecordNumber = bbReader.ReadInt32(false); // Byte 0 Record Number Integer 1 Big shape.ContentLength = bbReader.ReadInt32(false); // Byte 4 Content Length Integer 1 Big shape.ShapeType = (ShapeTypes)bbReader.ReadInt32(); // Byte 8 Shape Type Integer 1 Little shape.StartIndex = pointOffset; if (shape.ShapeType == ShapeTypes.NullShape) { continue; } bbReader.Read(allBounds, shp*32, 32); //double xMin = bbReader.ReadDouble(); // Byte 12 Xmin Double 1 Little // double yMin = bbReader.ReadDouble(); // Byte 20 Ymin Double 1 Little //double xMax = bbReader.ReadDouble(); // Byte 28 Xmax Double 1 Little //double yMax = bbReader.ReadDouble(); // Byte 36 Ymax Double 1 Little shape.NumParts = bbReader.ReadInt32(); // Byte 44 NumParts Integer 1 Little //feature.NumPoints = bbReader.ReadInt32(); // Byte 48 NumPoints Integer 1 Little shape.NumPoints = bbReader.ReadInt32(); // Create an envelope from the extents box in the file. //feature.Envelope = new Envelope(xMin, xMax, yMin, yMax); partOffsets[shp] = allParts.IntOffset(); allParts.Read(shape.NumParts * 4, bbReader); allCoords.Read(shape.NumPoints * 16, bbReader); pointOffset += shape.NumPoints; if (header.ShapeType == ShapeTypes.PolygonM) { // These are listed as "optional" but there isn't a good indicator of how to determine if they were added. // To handle the "optional" M values, check the contentLength for the feature. // The content length does not include the 8-byte record header and is listed in 16-bit words. if (shape.ContentLength * 2 > 44 + 4 * shape.NumParts + 16 * shape.NumPoints) { double mMin = bbReader.ReadDouble(); double mMax = bbReader.ReadDouble(); if(allM != null)allM.Read(shape.NumPoints * 8, bbReader); } } if (header.ShapeType == ShapeTypes.PolygonZ) { bool hasM = shape.ContentLength * 2 > 60 + 4 * shape.NumParts + 24 * shape.NumPoints; double zMin = bbReader.ReadDouble(); double zMax = bbReader.ReadDouble(); // For Z shapefiles, the Z part is not optional. if (allZ != null) allZ.Read(shape.NumPoints * 8, bbReader); // These are listed as "optional" but there isn't a good indicator of how to determine if they were added. // To handle the "optional" M values, check the contentLength for the feature. // The content length does not include the 8-byte record header and is listed in 16-bit words. if (hasM) { double mMin = bbReader.ReadDouble(); double mMax = bbReader.ReadDouble(); if (allM != null) allM.Read(shape.NumPoints * 8, bbReader); } } ShapeIndices.Add(shape); } double[] vert = allCoords.ToDoubleArray(); Vertex = vert; if (isM) M = allM.ToDoubleArray(); if (isZ) Z = allZ.ToDoubleArray(); List<ShapeRange> shapes = ShapeIndices; double[] bounds = new double[numShapes * 4]; Buffer.BlockCopy(allBounds, 0, bounds, 0, allBounds.Length); int[] parts = allParts.ToIntArray(); ProgressMeter = new ProgressMeter(ProgressHandler, "Testing Parts and Holes", numShapes); for (int shp = 0; shp < numShapes; shp++) { ShapeRange shape = shapes[shp]; shape.Extent = new Extent(bounds, shp * 4); for (int part = 0; part < shape.NumParts; part++) { int offset = partOffsets[shp]; int endIndex = shape.NumPoints + shape.StartIndex; int startIndex = parts[offset + part] + shape.StartIndex; if (part < shape.NumParts - 1) endIndex = parts[offset + part + 1] + shape.StartIndex; int count = endIndex - startIndex; PartRange partR = new PartRange(vert, shape.StartIndex, parts[offset + part], FeatureTypes.Polygon); partR.NumVertices = count; shape.Parts.Add(partR); } ProgressMeter.CurrentValue = shp; } ProgressMeter.Reset(); GC.Collect(); }
// ----------------------------------- FROM AND TO IN RAM ONLY --------------------------------- /// <summary> /// This creates an IN MEMORY ONLY window from the in-memory window of this raster. If, however, the requested range /// is outside of what is contained in the in-memory portions of this raster, an appropriate cast /// is required to ensure that you have the correct File handling, like a BinaryRaster etc. /// </summary> /// <param name="startRow">The 0 based integer index of the top row to get from this raster. If this raster is itself a window, 0 represents the startRow from the file.</param> /// <param name="endRow">The integer index of the bottom row to get from this raster. The largest allowed value is NumRows - 1.</param> /// <param name="startColumn">The 0 based integer index of the leftmost column to get from this raster. If this raster is a window, 0 represents the startColumn from the file.</param> /// <param name="endColumn">The 0 based integer index of the rightmost column to get from this raster. The largest allowed value is NumColumns - 1</param> /// <param name="inRam">Boolean. If this is true and the window is small enough, a copy of the values will be loaded To memory.</param> /// <returns>An implementation of IRaster</returns> public IRaster GetWindow(int startRow, int endRow, int startColumn, int endColumn, bool inRam) { if (IsInRam == false) { throw new ArgumentException(MessageStrings.RasterRequiresCast); } if (startRow < StartRow || endRow > EndRow || StartColumn < startColumn || EndColumn > endColumn) { // the requested extents are outside of the extents that have been windowed into ram. File Handling is required. throw new ArgumentException(MessageStrings.RasterRequiresCast); } int numCols = endColumn - startColumn + 1; int numRows = endRow - startRow + 1; ShortRaster result = new ShortRaster(numRows, numCols); result.Filename = Filename; result.Projection = Projection; result.DataType = typeof(short); result.NumRows = numRows; result.NumColumns = numCols; result.NumRowsInFile = NumRowsInFile; result.NumColumnsInFile = NumColumnsInFile; result.NoDataValue = NoDataValue; result.StartColumn = startColumn; result.StartRow = startRow; result.EndColumn = endColumn; result.EndRow = EndRow; result.FileType = FileType; // Reposition the new "raster" so that it matches the specified window, not the whole raster // X = [0] + [1] * column + [2] * row; // Y = [3] + [4] * column + [5] * row; result.Bounds = new RasterBounds(result.NumRows, result.NumColumns, new double[6]); result.Bounds.AffineCoefficients[0] = Bounds.AffineCoefficients[0] + Bounds.AffineCoefficients[1] * startColumn + Bounds.AffineCoefficients[2] * startRow; result.Bounds.AffineCoefficients[1] = Bounds.AffineCoefficients[1]; result.Bounds.AffineCoefficients[2] = Bounds.AffineCoefficients[2]; result.Bounds.AffineCoefficients[3] = Bounds.AffineCoefficients[3] + Bounds.AffineCoefficients[4] * startColumn + Bounds.AffineCoefficients[5] * startRow; result.Bounds.AffineCoefficients[4] = Bounds.AffineCoefficients[4]; result.Bounds.AffineCoefficients[5] = Bounds.AffineCoefficients[5]; // Now we can copy any values currently in memory. ProgressMeter pm = new ProgressMeter(ProgressHandler, MessageStrings.CopyingValues, endRow); pm.StartValue = startRow; // copy values directly using both data structures for (int row = 0; row < numRows; row++) { for (int col = 0; col < numCols; col++) { result.Data[row][col] = Data[startRow + row][startColumn + col]; } pm.CurrentValue = row; } pm.Reset(); result.Value = new ShortValueGrid(result); return result; }
/// <summary> /// This populates the Table with data from the file. /// </summary> /// <param name="numRows">In the event that the dbf file is not found, this indicates how many blank rows should exist in the attribute Table.</param> public void Fill(int numRows) { if (!_loaded) Load(); _dataRowWatch = new Stopwatch(); _dataTable.Rows.Clear(); // if we have already loaded data, clear the data. if (File.Exists(_filename) == false) { _numRecords = numRows; _dataTable.BeginLoadData(); _dataTable.Columns.Add("FID", typeof (int)); for (int row = 0; row < numRows; row++) { DataRow dr = _dataTable.NewRow(); dr["FID"] = row; _dataTable.Rows.Add(dr); } _dataTable.EndLoadData(); return; } Stopwatch sw = new Stopwatch(); sw.Start(); ProgressMeter = new ProgressMeter(ProgressHandler, "Reading from DBF Table...", _numRecords); if (_numRecords < 10000000) ProgressMeter.StepPercent = 5; if (_numRecords < 5000000) ProgressMeter.StepPercent = 10; if (_numRecords < 100000) ProgressMeter.StepPercent = 50; if (_numRecords < 10000) ProgressMeter.StepPercent = 100; _dataTable.BeginLoadData(); // Reading the Table elements as well as the shapes in a single progress loop. for (int row = 0; row < _numRecords; row++) { // --------- DATABASE --------- CurrentFeature = ReadTableRow(myReader); try { _dataTable.Rows.Add(ReadTableRowFromChars(row)); } catch (Exception ex) { Debug.WriteLine(ex.ToString()); _dataTable.Rows.Add(_dataTable.NewRow()); } // If a progress message needs to be updated, this will handle that. ProgressMeter.CurrentValue = row; } ProgressMeter.Reset(); _dataTable.EndLoadData(); sw.Stop(); Debug.WriteLine("Load Time:" + sw.ElapsedMilliseconds + " Milliseconds"); Debug.WriteLine("Conversion:" + _dataRowWatch.ElapsedMilliseconds + " Milliseconds"); _attributesPopulated = true; OnAttributesFilled(); }
/// <summary> /// Reads all the information from the specified file. This also sends status messages through progressHandler. /// </summary> public void Open(IProgressHandler progressHandler) { IFeature currentFeature; string dbfFile = Path.ChangeExtension(Filename, ".dbf"); FileStream myStream = new FileStream(dbfFile, FileMode.Open, FileAccess.Read, FileShare.Read); BinaryReader myReader = new BinaryReader(myStream); ReadTableHeader(myReader); // based on the header, set up the fields information etc. ProgressMeter pm = new ProgressMeter(progressHandler, "Opening " + Path.GetFileName(Filename), _numRecords); ShapeReader myShapeReader = new ShapeReader(Filename); IEnumerator en = myShapeReader.GetEnumerator(); en.MoveNext(); // Reading the Table elements as well as the shapes in a single progress loop. for (int row = 0; row < _numRecords; row++) { // --------- DATABASE --------- CurrentFeature = ReadTableRow(myReader); // rem this line if the DATABASE is turned back on currentFeature = new Feature(); currentFeature.BasicGeometry = (IBasicGeometry)en.Current; en.MoveNext(); Features.Add(currentFeature); // --------- DATABASE --------- _Table.Rows.Add(CurrentFeature.DataRow); // If a progress message needs to be updated, this will handle that. pm.CurrentValue = row; } Envelope = null; // invalidate the envelope so that it will be re-calculated from all the points pm.Reset(); // Shows the basic "Ready." message indicating that we are done with this step. }
// ------------------------------------------FROM AND TO IN RAM ONLY ----------------- /// <summary> /// This creates a completely new raster from the windowed domain on the original raster. This new raster /// will not have a source file, and values like NumRowsInFile will correspond to the in memory version. /// All the values will be copied to the new source file. InRam must be true at this level. /// </summary> /// <param name="filename"></param> /// <param name="startRow">The 0 based integer index of the top row to copy from this raster. If this raster is itself a window, 0 represents the startRow from the file.</param> /// <param name="endRow">The integer index of the bottom row to copy from this raster. The largest allowed value is NumRows - 1.</param> /// <param name="startColumn">The 0 based integer index of the leftmost column to copy from this raster. If this raster is a window, 0 represents the startColumn from the file.</param> /// <param name="endColumn">The 0 based integer index of the rightmost column to copy from this raster. The largest allowed value is NumColumns - 1</param> /// <param name="copyValues">If this is true, the valeus are saved to the file. If this is false and the data can be loaded into Ram, no file handling is done. Otherwise, a file of NoData values is created.</param> /// <param name="inRam">Boolean. If this is true and the window is small enough, a copy of the values will be loaded into memory.</param> /// <returns>An implementation of IRaster</returns> public IRaster CopyWindow(string filename, int startRow, int endRow, int startColumn, int endColumn, bool copyValues, bool inRam) { if (inRam == false || (endColumn - startColumn + 1) * (endRow - startRow + 1) > 64000000) { throw new ArgumentException(MessageStrings.RasterRequiresCast); } if (IsInRam == false) { throw new ArgumentException(MessageStrings.RasterRequiresCast); } int numCols = endColumn - startColumn + 1; int numRows = endRow - startRow + 1; ShortRaster result = new ShortRaster(numRows, numCols); result.Projection = Projection; // The affine coefficients defining the world file are the same except that they are translated over. Only the position of the // upper left corner changes. Everything else is the same as the previous raster. // X = [0] + [1] * column + [2] * row; // Y = [3] + [4] * column + [5] * row; result.Bounds = new RasterBounds(result.NumRows, result.NumColumns, new double[6]); result.Bounds.AffineCoefficients[0] = Bounds.AffineCoefficients[0] + Bounds.AffineCoefficients[1] * startColumn + Bounds.AffineCoefficients[2] * startRow; result.Bounds.AffineCoefficients[1] = Bounds.AffineCoefficients[1]; result.Bounds.AffineCoefficients[2] = Bounds.AffineCoefficients[2]; result.Bounds.AffineCoefficients[3] = Bounds.AffineCoefficients[3] + Bounds.AffineCoefficients[4] * startColumn + Bounds.AffineCoefficients[5] * startRow; result.Bounds.AffineCoefficients[4] = Bounds.AffineCoefficients[4]; result.Bounds.AffineCoefficients[5] = Bounds.AffineCoefficients[5]; ProgressMeter pm = new ProgressMeter(ProgressHandler, MessageStrings.CopyingValues, numRows); // copy values directly using both data structures for (int row = 0; row < numRows; row++) { for (int col = 0; col < numCols; col++) { result.Data[row][col] = Data[startRow + row][startColumn + col]; } pm.CurrentValue = row; } pm.Reset(); result.Value = new ShortValueGrid(result); return result; }
/// <summary> /// Gets the count of members that match the expression /// </summary> /// <param name="expressions">The string expression to test</param> /// <param name="progressHandler">THe progress handler that can also cancel the counting</param> /// <param name="maxSampleSize">The integer maximum sample size from which to draw counts. If this is negative, it will not be used.</param> /// <returns>The integer count of the memebrs that match the expression.</returns> public override int[] GetCounts(string[] expressions, ICancelProgressHandler progressHandler, int maxSampleSize) { if (InternalDataSet != null) return InternalDataSet.GetCounts(expressions, progressHandler, maxSampleSize); if (AttributesPopulated) return base.GetCounts(expressions, progressHandler, maxSampleSize); int[] counts = new int[expressions.Length]; // The most common case would be no filter expression, in which case the count is simply the number of shapes. bool requiresRun = false; for(int iex = 0; iex < expressions.Length;iex++) { if (!string.IsNullOrEmpty(expressions[iex])) { requiresRun = true; } else { counts[iex] = NumRows(); } } if (!requiresRun) return counts; AttributePager ap = new AttributePager(this, 5000); ProgressMeter pm = new ProgressMeter(progressHandler, "Calculating Counts", ap.NumPages()); // Don't bother to use a sampling approach if the number of rows is on the same order of magnitude as the number of samples. if(maxSampleSize > 0 && maxSampleSize < NumRows()/2) { DataTable sample = new DataTable(); sample.Columns.AddRange(GetColumns()); Dictionary<int, int> usedRows = new Dictionary<int, int>(); int samplesPerPage = maxSampleSize/ap.NumPages(); Random rnd = new Random(DateTime.Now.Millisecond); for (int page = 0; page < ap.NumPages(); page++) { for (int i = 0; i < samplesPerPage; i++ ) { int row; do { row = rnd.Next(ap.StartIndex, ap.StartIndex + ap.PageSize); } while (usedRows.ContainsKey(row)); usedRows.Add(row, row); sample.Rows.Add(ap.Row(row).ItemArray); } ap.MoveNext(); pm.CurrentValue = page; if (progressHandler.Cancel) break; System.Windows.Forms.Application.DoEvents(); } for (int i = 0; i < expressions.Length; i++) { try { DataRow[] dr = sample.Select(expressions[i]); if (dr != null) counts[i] += dr.Length; } catch (Exception) { } } pm.Reset(); return counts; } for (int page = 0; page < ap.NumPages(); page++) { for (int i = 0; i < expressions.Length; i++) { DataRow[] dr = ap[page].Select(expressions[i]); if(dr != null)counts[i] += dr.Length; } pm.CurrentValue = page; if (progressHandler.Cancel) break; System.Windows.Forms.Application.DoEvents(); } pm.Reset(); return counts; }
private void ReadRGB() { if (_dataset.RasterCount < 3) { throw new GdalException("RGB Format was indicated but there are only " + _dataset.RasterCount + " bands!"); } _green = _dataset.GetRasterBand(2); _blue = _dataset.GetRasterBand(3); int tw = TileCollection.TileWidth; int th = TileCollection.TileHeight; int ntt = TileCollection.NumTilesTall(); int ntw = TileCollection.NumTilesWide(); ProgressMeter pm = new ProgressMeter(_prog, "Reading Tiles ", ntt*ntw); for (int row = 0; row < ntt; row++) { for (int col = 0; col < ntw; col++) { int width = TileCollection.GetTileWidth(col); int height = TileCollection.GetTileHeight(row); MWImageData id = new MWImageData(width, height); Bitmap image = new Bitmap(width, height, PixelFormat.Format32bppArgb); byte[] red = new byte[width*height]; byte[] g = new byte[width*height]; byte[] b = new byte[width*height]; _red.ReadRaster(col * tw, row * th, width, height, red, width, height, 0, 0); _green.ReadRaster(col * tw, row * th, width, height, g, width, height, 0, 0); _blue.ReadRaster(col * tw, row * th, width, height, b, width, height, 0, 0); BitmapData bData = image.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); Stride = bData.Stride; image.UnlockBits(bData); byte[] vals = new byte[width*height*4]; int stride = Stride; const int bpp = 4; for (int r = 0; r < height; r++) { for (int c = 0; c < width; c++) { vals[r*stride + c*bpp] = b[r*width + c]; vals[r*stride + c*bpp + 1] = g[r*width + c]; vals[r*stride + c*bpp + 2] = red[r*width + c]; vals[r*stride + c*bpp + 3] = 255; } } id.Values = vals; id.WriteBytes(); TileCollection.Tiles[row, col] = id; pm.CurrentValue = row*ntw + col; } } pm.Reset(); SetTileBounds(Bounds.AffineCoefficients); }
/// <summary> /// Creates a bitmap using only the colorscheme, even if a hillshade was specified /// </summary> /// <param name="bitmap">The bitmap to edit. Ensure that this has been created and saved at least once</param> /// <param name="progressHandler">An IProgressHandler</param> /// <param name="rasterSymbolizer">The raster symbolizer to use</param> /// <exception cref="MapWindow.Main.NullLogException">rasterSymbolizer cannot be null</exception> public virtual void PaintColorSchemeToBitmap(IRasterSymbolizer rasterSymbolizer, Bitmap bitmap, IProgressHandler progressHandler) { Debug.WriteLine("IntRaster - PaintColorSchemeToBitamp"); BitmapData bmpData; if (Data == null) return; if (rasterSymbolizer == null) throw new NullLogException("rasterSymbolizer"); if (rasterSymbolizer.Scheme == null || rasterSymbolizer.Scheme.Categories == null || rasterSymbolizer.Scheme.Categories.Count == 0) return; // Create a new Bitmap and use LockBits combined with Marshal.Copy to get an array of bytes to work with. Rectangle rect = new Rectangle(0, 0, NumColumns, NumRows); try { bmpData = bitmap.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); } catch (ArgumentException ex) { if (ex.ParamName == "format") throw new BitmapFormatException(); LogManager.DefaultLogManager.Exception(ex); throw; } int numBytes = bmpData.Stride*bmpData.Height; byte[] rgbData = new byte[numBytes]; Marshal.Copy(bmpData.Scan0, rgbData, 0, numBytes); Color pixelColor; ProgressMeter pm = new ProgressMeter(progressHandler, MessageStrings.PaintingColorScheme, NumRows); if (NumRows*NumColumns < 100000) pm.StepPercent = 50; if (NumRows*NumColumns < 500000) pm.StepPercent = 10; if (NumRows*NumColumns < 1000000) pm.StepPercent = 5; for (int row = 0; row < NumRows; row++) { for (int col = 0; col < NumColumns; col++) { // use the colorbreaks to calculate the colors pixelColor = rasterSymbolizer.GetColor(Data[row][col]); // control transparency here int alpha = Convert.ToInt32(rasterSymbolizer.Opacity*255); if (alpha > 255) alpha = 255; if (alpha < 0) alpha = 0; byte a = (byte) alpha; byte r = pixelColor.R; byte g = pixelColor.G; byte b = pixelColor.B; int offset = row*bmpData.Stride + col*4; rgbData[offset] = b; rgbData[offset + 1] = g; rgbData[offset + 2] = r; rgbData[offset + 3] = a; } pm.CurrentValue = row; } pm.Reset(); // Copy the values back into the bitmap Marshal.Copy(rgbData, 0, bmpData.Scan0, numBytes); bitmap.UnlockBits(bmpData); rasterSymbolizer.ColorSchemeHasUpdated = true; return; }
/// <summary> /// Creates a bitmap based on the specified RasterSymbolizer /// </summary> /// <returns></returns> /// <exception cref="MapWindow.Main.NullLogException">rasterSymbolizer cannot be null</exception> public virtual void DrawToBitmap(IRasterSymbolizer rasterSymbolizer, Bitmap bitmap, IProgressHandler progressHandler) { Debug.WriteLine("IntRaster Calculated Bitmap"); BitmapData bmpData; if (Data == null) return; if (rasterSymbolizer == null) throw new NullLogException("rasterSymbolizer"); if (rasterSymbolizer.Scheme == null || rasterSymbolizer.Scheme.Categories == null || rasterSymbolizer.Scheme.Categories.Count == 0) return; // Create a new Bitmap and use LockBits combined with Marshal.Copy to get an array of bytes to work with. Rectangle rect = new Rectangle(0, 0, NumColumns, NumRows); try { bmpData = bitmap.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); } catch (ArgumentException ex) { if (ex.ParamName == "format") throw new BitmapFormatException(); LogManager.DefaultLogManager.Exception(ex); throw; } int numBytes = bmpData.Stride*bmpData.Height; byte[] rgbData = new byte[numBytes]; Marshal.Copy(bmpData.Scan0, rgbData, 0, numBytes); bool useHillShade = false; float[][] hillshade = rasterSymbolizer.HillShade; if (rasterSymbolizer.ShadedRelief.IsUsed) { hillshade = rasterSymbolizer.HillShade; useHillShade = true; } Color pixelColor; ProgressMeter pm = new ProgressMeter(progressHandler, MessageStrings.CreatingTexture, NumRows); if (NumRows*NumColumns < 100000) pm.StepPercent = 50; if (NumRows*NumColumns < 500000) pm.StepPercent = 10; if (NumRows*NumColumns < 1000000) pm.StepPercent = 5; for (int row = 0; row < NumRows; row++) { for (int col = 0; col < NumColumns; col++) { // use the colorbreaks to calculate the colors pixelColor = rasterSymbolizer.GetColor(Data[row][col]); // control transparency here int alpha = Convert.ToInt32(rasterSymbolizer.Opacity*255); if (alpha > 255) alpha = 255; if (alpha < 0) alpha = 0; byte a = (byte) alpha; byte r, g, b; if (useHillShade && hillshade != null) { if (hillshade[row][col] == -1) { pixelColor = rasterSymbolizer.NoDataColor; r = pixelColor.R; g = pixelColor.G; b = pixelColor.B; } else { int red = Convert.ToInt32(pixelColor.R*hillshade[row][col]); int green = Convert.ToInt32(pixelColor.G*hillshade[row][col]); int blue = Convert.ToInt32(pixelColor.B*hillshade[row][col]); if (red > 255) red = 255; if (green > 255) green = 255; if (blue > 255) blue = 255; if (red < 0) red = 0; if (green < 0) green = 0; if (blue < 0) blue = 0; b = (byte) blue; r = (byte) red; g = (byte) green; } } else { r = pixelColor.R; g = pixelColor.G; b = pixelColor.B; } int offset = row*bmpData.Stride + col*4; rgbData[offset] = b; rgbData[offset + 1] = g; rgbData[offset + 2] = r; rgbData[offset + 3] = a; } pm.CurrentValue = row; } pm.Reset(); if (rasterSymbolizer.IsSmoothed) { Smoother sm = new Smoother(bmpData, rgbData, progressHandler); rgbData = sm.Smooth(); } // Copy the values back into the bitmap Marshal.Copy(rgbData, 0, bmpData.Scan0, numBytes); bitmap.UnlockBits(bmpData); rasterSymbolizer.ColorSchemeHasUpdated = true; return; }
/// <summary> /// Saves the file to a new location /// </summary> /// <param name="filename">The filename to save</param> /// <param name="overwrite">Boolean that specifies whether or not to overwrite the existing file</param> public override void SaveAs(string filename, bool overwrite) { if(IndexMode) { SaveAsIndexed(filename, overwrite); return; } if (File.Exists(filename) && filename != Filename && overwrite == false) { if (MessageBox.Show("The file already exists. Do you wish to overwrite it?", "File Exists", MessageBoxButtons.YesNo) == DialogResult.No) return; File.Delete(filename); } string dir = Path.GetDirectoryName(filename); if (!Directory.Exists(dir)) { if (MessageBox.Show("Directory " + dir + " does not exist. Do you want to create it?", "Create Directory?", MessageBoxButtons.YesNo) != DialogResult.OK) return; Directory.CreateDirectory(dir); } InvalidateEnvelope(); Header.Xmin = Envelope.Minimum.X; Header.Xmax = Envelope.Maximum.X; Header.Ymin = Envelope.Minimum.Y; Header.Ymax = Envelope.Maximum.Y; if (CoordinateType == CoordinateTypes.Regular) { Header.ShapeType = ShapeTypes.MultiPoint; } if (CoordinateType == CoordinateTypes.M) { Header.ShapeType = ShapeTypes.MultiPointM; } if (CoordinateType == CoordinateTypes.Z) { Header.ShapeType = ShapeTypes.MultiPointZ; } if (Header.ShapeType == ShapeTypes.MultiPoint || Header.ShapeType == ShapeTypes.MultiPointM) { // test to see if the coordinates have added z or m values in the first coordinate Coordinate c = Features[0].BasicGeometry.Coordinates[0]; if (!double.IsNaN(c.Z)) { Header.ShapeType = ShapeTypes.MultiPointZ; } } if (Header.ShapeType == ShapeTypes.MultiPointZ) { Header.Zmin = Envelope.Minimum.Z; Header.Zmax = Envelope.Maximum.Z; } if (Header.ShapeType == ShapeTypes.MultiPointM || Header.ShapeType == ShapeTypes.MultiPointZ) { Header.Mmin = Envelope.Minimum.M; Header.Mmax = Envelope.Maximum.M; } Header.ShxLength = 50 + 4 * Features.Count; Header.SaveAs(filename); IO.BufferedBinaryWriter bbWriter = new IO.BufferedBinaryWriter(filename); IO.BufferedBinaryWriter indexWriter = new IO.BufferedBinaryWriter(Header.ShxFilename); int fid = 0; int offset = 50; // the shapefile header starts at 100 bytes, so the initial offset is 50 words int contentLength = 0; ProgressMeter = new ProgressMeter(ProgressHandler, "Saving (Not Indexed)...", Features.Count); foreach (IFeature f in Features) { offset += contentLength; // adding the previous content length from each loop calculates the word offset List<Coordinate> points = new List<Coordinate>(); contentLength = 20; for (int iPart = 0; iPart < f.NumGeometries; iPart++) { IList<Coordinate> coords = f.BasicGeometry.GetBasicGeometryN(iPart).Coordinates; foreach (Coordinate coord in coords) { points.Add(coord); } } if (Header.ShapeType == ShapeTypes.MultiPoint) { contentLength += points.Count * 8; } if (Header.ShapeType == ShapeTypes.MultiPointM) { contentLength += 8; // mmin, mmax contentLength += points.Count * 12; } if (Header.ShapeType == ShapeTypes.MultiPointZ) { contentLength += 16; // mmin, mmax, zmin, zmax contentLength += points.Count * 16; } // Index File // --------------------------------------------------------- // Position Value Type Number Byte Order // --------------------------------------------------------- indexWriter.Write(offset, false); // Byte 0 Offset Integer 1 Big indexWriter.Write(contentLength, false); // Byte 4 Content Length Integer 1 Big // X Y Poly Lines // --------------------------------------------------------- // Position Value Type Number Byte Order // --------------------------------------------------------- bbWriter.Write(fid+1, false); // Byte 0 Record Number Integer 1 Big bbWriter.Write(contentLength, false); // Byte 4 Content Length Integer 1 Big bbWriter.Write((int)Header.ShapeType); // Byte 8 Shape Type 3 Integer 1 Little if (Header.ShapeType == ShapeTypes.NullShape) { continue; } bbWriter.Write(f.Envelope.Minimum.X); // Byte 12 Xmin Double 1 Little bbWriter.Write(f.Envelope.Minimum.Y); // Byte 20 Ymin Double 1 Little bbWriter.Write(f.Envelope.Maximum.X); // Byte 28 Xmax Double 1 Little bbWriter.Write(f.Envelope.Maximum.Y); // Byte 36 Ymax Double 1 Little bbWriter.Write(points.Count); // Byte 44 NumPoints Integer 1 Little foreach (Coordinate coord in points) // Byte X Points Point NumPoints Little { bbWriter.Write(coord.X); bbWriter.Write(coord.Y); //if (Header.ShapeType == ShapeTypes.MultiPointZ) //{ // bbWriter.Write(coord.Z); //} } if (Header.ShapeType == ShapeTypes.MultiPointZ) { bbWriter.Write(f.Envelope.Minimum.Z); bbWriter.Write(f.Envelope.Maximum.Z); foreach (Coordinate coord in points) // Byte X Points Point NumPoints Little { bbWriter.Write(coord.Z); } } if (Header.ShapeType == ShapeTypes.MultiPointM || Header.ShapeType == ShapeTypes.MultiPointZ) { if(f.Envelope == null) { bbWriter.Write(0.0); bbWriter.Write(0.0); } else { bbWriter.Write(f.Envelope.Minimum.M); bbWriter.Write(f.Envelope.Maximum.M); } foreach (Coordinate coord in points) // Byte X Points Point NumPoints Little { bbWriter.Write(coord.M); } } ProgressMeter.CurrentValue = fid; fid++; offset += 4; } ProgressMeter.Reset(); bbWriter.Close(); indexWriter.Close(); offset += contentLength; WriteFileLength(Filename, offset); UpdateAttributes(); SaveProjection(); }
/// <summary> /// Creates a bitmap based on the specified RasterSymbolizer /// </summary> /// <param name="bitmap"> the bitmap to paint to</param> /// <param name="progressHandler">The progress handler</param> /// <exception cref="MapWindow.Main.NullLogException">rasterSymbolizer cannot be null</exception> public void PaintShadingToBitmap(Bitmap bitmap, IProgressHandler progressHandler) { System.Drawing.Imaging.BitmapData bmpData; if (_hillshade == null) { return; } // Create a new Bitmap and use LockBits combined with Marshal.Copy to get an array of bytes to work with. Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height); try { bmpData = bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format32bppArgb); } catch (ArgumentException ex) { if (ex.ParamName == "format") { throw new BitmapFormatException(); } Components.LogManager.DefaultLogManager.Exception(ex); throw; } int numBytes = bmpData.Stride * bmpData.Height; byte[] rgbData = new byte[numBytes]; System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, rgbData, 0, numBytes); float[][] hillshade = _hillshade; ProgressMeter pm = new ProgressMeter(progressHandler, MessageStrings.PaintingHillshade, bitmap.Height); if (bitmap.Width * bitmap.Height < 100000) pm.StepPercent = 50; if (bitmap.Width * bitmap.Height < 500000) pm.StepPercent = 10; if (bitmap.Width * bitmap.Height < 1000000) pm.StepPercent = 5; for (int row = 0; row < bitmap.Height; row++) { for (int col = 0; col < bitmap.Width; col++) { int offset = row * bmpData.Stride + col * 4; byte b = rgbData[offset]; byte g = rgbData[offset + 1]; byte r = rgbData[offset + 2]; // rgbData[offset + 3] = a; don't worry about alpha int red = Convert.ToInt32(r * hillshade[row][col]); int green = Convert.ToInt32(g * hillshade[row][col]); int blue = Convert.ToInt32(b * hillshade[row][col]); if (red > 255) red = 255; if (green > 255) green = 255; if (blue > 255) blue = 255; if (red < 0) red = 0; if (green < 0) green = 0; if (blue < 0) blue = 0; b = (byte)blue; r = (byte)red; g = (byte)green; rgbData[offset] = b; rgbData[offset + 1] = g; rgbData[offset + 2] = r; } pm.CurrentValue = row; } pm.Reset(); // Copy the values back into the bitmap System.Runtime.InteropServices.Marshal.Copy(rgbData, 0, bmpData.Scan0, numBytes); bitmap.UnlockBits(bmpData); return; }
/// <summary> /// Create Hillshade of values ranging from 0 to 1, or -1 for no-data regions. /// This should be a little faster since we are accessing the Data field directly instead of working /// through a value parameter. /// </summary> /// <param name="raster">The raster to create the hillshade from.</param> /// <param name="shadedRelief">An implementation of IShadedRelief describing how the hillshade should be created.</param> /// <param name="progressHandler">An implementation of IProgressHandler for progress messages</param> public static float[][] CreateHillShade(this IRaster raster, IShadedRelief shadedRelief, IProgressHandler progressHandler) { int numCols = raster.NumColumns; int numRows = raster.NumRows; double noData = raster.NoDataValue; float extrusion = shadedRelief.Extrusion; float elevationFactor = shadedRelief.ElevationFactor; float lightIntensity = shadedRelief.LightIntensity; float ambientIntensity = shadedRelief.AmbientIntensity; FloatVector3 lightDirection = shadedRelief.GetLightDirection(); float[] aff = new float[6]; // affine coefficients converted to float format for (int i = 0; i < 6; i++) { aff[i] = Convert.ToSingle(raster.Bounds.AffineCoefficients[i]); } float[][] hillshade = new float[numRows][]; ProgressMeter pm = new ProgressMeter(progressHandler, MessageStrings.CreatingShadedRelief, numRows); for (int row = 0; row < numRows; row++) { hillshade[row] = new float[numCols]; for (int col = 0; col < numCols; col++) { // 3D position vectors of three points to create a triangle. FloatVector3 v1 = new FloatVector3(0f, 0f, 0f); FloatVector3 v2 = new FloatVector3(0f, 0f, 0f); FloatVector3 v3 = new FloatVector3(0f, 0f, 0f); double val = raster.Value[row, col]; // Cannot compute polygon ... make the best guess if (col >= numCols - 1 || row <= 0) { if (col >= numCols - 1 && row <= 0) { v1.Z = (float)val; v2.Z = (float)val; v3.Z = (float)val; } else if (col >= numCols - 1) { v1.Z = (float)raster.Value[row, col - 1]; // 3 - 2 v2.Z = (float)raster.Value[row - 1, col]; // | / v3.Z = (float)raster.Value[row - 1, col - 1]; // 1 * } else if (row <= 0) { v1.Z = (float)raster.Value[row + 1, col]; // 3* 2 v2.Z = (float)raster.Value[row, col + 1]; // | / v3.Z = (float)val; // 1 } } else { v1.Z = (float)val; // 3 - 2 v2.Z = (float)raster.Value[row - 1, col + 1]; // | / v3.Z = (float)raster.Value[row - 1, col]; // 1* } // Test for no-data values and don't calculate hillshade in that case if (v1.Z == noData || v2.Z == noData || v3.Z == noData) { hillshade[row][col] = -1; // should never be negative otherwise. continue; } // Apply the Conversion Factor to put elevation into the same range as lat/lon v1.Z = v1.Z * elevationFactor * extrusion; v2.Z = v2.Z * elevationFactor * extrusion; v3.Z = v3.Z * elevationFactor * extrusion; // Complete the vectors using the latitude/longitude coordinates v1.X = aff[0] + aff[1] * col + aff[2] * row; v1.Y = aff[3] + aff[4] * col + aff[5] * row; v2.X = aff[0] + aff[1] * (col + 1) + aff[2] * (row + 1); v2.Y = aff[3] + aff[4] * (col + 1) + aff[5] * (row + 1); v3.X = aff[0] + aff[1] * col + aff[2] * (row + 1); v3.Y = aff[3] + aff[4] * col + aff[5] * (row + 1); // We need two direction vectors in order to obtain a cross product FloatVector3 dir2 = FloatVector3.Subtract(v2, v1); // points from 1 to 2 FloatVector3 dir3 = FloatVector3.Subtract(v3, v1); // points from 1 to 3 FloatVector3 cross = FloatVector3.CrossProduct(dir3, dir2); // right hand rule - cross direction should point into page... reflecting more if light direction is in the same direction // Normalizing this vector ensures that this vector is a pure direction and won't affect the intensity cross.Normalize(); // Hillshade now has an "intensity" modifier that should be applied to the R, G and B values of the color found at each pixel. hillshade[row][col] = FloatVector3.Dot(cross, lightDirection) * lightIntensity + ambientIntensity; } pm.CurrentValue = row; } pm.Reset(); // Setting this indicates that a hillshade has been created more recently than characteristics have been changed. shadedRelief.HasChanged = false; return hillshade; }
private void CreateUniqueCategories(string fieldName, IAttributeSource source, ICancelProgressHandler progressHandler) { Breaks = GetUniqueValues(fieldName, source, progressHandler); string fieldExpression = "[" + fieldName.ToUpper() + "]"; ClearCategories(); bool isStringField = CheckFieldType(fieldName, source); ProgressMeter pm = new ProgressMeter(progressHandler, "Building Feature Categories", Breaks.Count); List<double> sizeRamp = GetSizeSet(Breaks.Count); List<Color> colorRamp = GetColorSet(Breaks.Count); for (int colorIndex = 0; colorIndex < Breaks.Count; colorIndex++) { Break brk = Breaks[colorIndex]; //get the color for the category Color randomColor = colorRamp[colorIndex]; double size = sizeRamp[colorIndex]; IFeatureCategory cat = CreateNewCategory(randomColor, size) as IFeatureCategory; if (cat != null) { //cat.SelectionSymbolizer = _selectionSymbolizer.Copy(); cat.LegendText = brk.Name; if (isStringField) cat.FilterExpression = fieldExpression + "= '" + brk.Name.Replace("'", "''") + "'"; else cat.FilterExpression = fieldExpression + "=" + brk.Name; AddCategory(cat); } colorIndex++; pm.CurrentValue = colorIndex; } pm.Reset(); }
/// <summary> /// Creates a bitmap from this raster using the specified rasterSymbolizer /// </summary> /// <param name="raster">The raster to draw to a bitmap</param> /// <param name="rasterSymbolizer">The raster symbolizer to use for assigning colors</param> /// <param name="bitmap">This must be an Format32bbpArgb bitmap that has already been saved to a file so that it exists.</param> /// <param name="progressHandler">The progress handler to use.</param> /// <returns>A System.Drawing.Bitmap if the operation was successful or null.</returns> /// <exception cref="MapWindow.Main.NullLogException">rasterSymbolizer cannot be null</exception> public static void DrawToBitmap(this IRaster raster, IRasterSymbolizer rasterSymbolizer, Bitmap bitmap, IProgressHandler progressHandler) { System.Drawing.Imaging.BitmapData bmpData; if (rasterSymbolizer == null) { throw new NullLogException("rasterSymbolizer"); } if (rasterSymbolizer.Scheme.Categories == null || rasterSymbolizer.Scheme.Categories.Count == 0) return; Rectangle rect = new Rectangle(0, 0, raster.NumColumns, raster.NumRows); try { bmpData = bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); } catch(Exception ex) { string originalError = ex.ToString(); // if they have not saved the bitmap yet, it can cause an exception System.IO.MemoryStream ms = new System.IO.MemoryStream(); bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp); ms.Position = 0; bmpData = bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); // any further exceptions should simply throw exceptions to allow easy debugging } int numBytes = bmpData.Stride * bmpData.Height; byte[] rgbData = new byte[numBytes]; System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, rgbData, 0, numBytes); bool useHillShade = false; float[][] hillshade = rasterSymbolizer.HillShade; if (rasterSymbolizer.ShadedRelief.IsUsed) { hillshade = rasterSymbolizer.HillShade; useHillShade = true; } Color pixelColor; ProgressMeter pm = new ProgressMeter(progressHandler, "Recreating Bitmap", raster.NumRows); try { for (int row = 0; row < raster.NumRows; row++) { for (int col = 0; col < raster.NumColumns; col++) { // use the colorbreaks to calculate the colors pixelColor = rasterSymbolizer.GetColor(raster.Value[row, col]); // control transparency here float alpha = rasterSymbolizer.Opacity * 255f; if (alpha > 255f) alpha = 255f; if (alpha < 0f) alpha = 0f; byte a = Convert.ToByte(alpha); byte g; byte r; byte b; if (useHillShade && hillshade != null) { if (hillshade[row][col] == -1 || float.IsNaN(hillshade[row][col])) { pixelColor = rasterSymbolizer.NoDataColor; r = pixelColor.R; g = pixelColor.G; b = pixelColor.B; } else { float red = pixelColor.R * hillshade[row][col]; float green = pixelColor.G * hillshade[row][col]; float blue = pixelColor.B * hillshade[row][col]; if (red > 255f) red = 255f; if (green > 255f) green = 255f; if (blue > 255f) blue = 255f; if (red < 0f) red = 0f; if (green < 0f) green = 0f; if (blue < 0f) blue = 0f; b = Convert.ToByte(blue); r = Convert.ToByte(red); g = Convert.ToByte(green); } } else { r = pixelColor.R; g = pixelColor.G; b = pixelColor.B; } int offset = row * bmpData.Stride + col * 4; rgbData[offset] = b; rgbData[offset + 1] = g; rgbData[offset + 2] = r; rgbData[offset + 3] = a; } pm.CurrentValue = row; } } catch { System.Diagnostics.Debug.WriteLine(" Unable to write data to raster."); } pm.Reset(); if (rasterSymbolizer.IsSmoothed) { Smoother mySmoother = new Smoother(bmpData, rgbData, progressHandler); rgbData = mySmoother.Smooth(); } // Copy the values back into the bitmap System.Runtime.InteropServices.Marshal.Copy(rgbData, 0, bmpData.Scan0, numBytes); bitmap.UnlockBits(bmpData); rasterSymbolizer.ColorSchemeHasUpdated = true; return; }
// ------------------------------------ IN RAM ONLY ------------------------------------------------------------ /// <summary> /// Gets the statistics all the values, but only if this raster is InRam and fully windowed. Statistics from a file based /// raster will require casting to the appropriate file type. /// </summary> public override void GetStatistics() { if (IsInRam == false || this.IsFullyWindowed() == false) { throw new ArgumentException(MessageStrings.RasterRequiresCast); } ProgressMeter pm = new ProgressMeter(ProgressHandler, MessageStrings.CalculatingStatistics, NumRows); short min = short.MaxValue; short max = short.MinValue; double total = 0; double sqrTotal = 0; int count = 0; for (int row = 0; row < NumRows; row++) { for (int col = 0; col < NumColumns; col++) { short val = Data[row][col]; if (val.CompareTo(_shortNoDataValue) != 0) { if (val.CompareTo(max) > 0) max = val; if (val.CompareTo(min) < 0) min = val; double dblVal = val; total += dblVal; sqrTotal += dblVal * dblVal; count++; } } pm.CurrentValue = row; } Minimum = min; Maximum = max; NumValueCells = count; StdDeviation = (short)Math.Sqrt((sqrTotal / NumValueCells) - (total / NumValueCells) * (total / NumValueCells)); pm.Reset(); }
/// <summary> /// Creates a bitmap using only the colorscheme, even if a hillshade was specified /// </summary> /// <param name="raster">The Raster containing values that need to be drawn to the bitmap as a color scheme.</param> /// <param name="bitmap">The bitmap to edit. Ensure that this has been created and saved at least once</param> /// <param name="progressHandler">An IProgressHandler</param> /// <param name="rasterSymbolizer">The raster symbolizer to use</param> /// <exception cref="MapWindow.Main.NullLogException">rasterSymbolizer cannot be null</exception> public static void PaintColorSchemeToBitmap(this IRaster raster, IRasterSymbolizer rasterSymbolizer, Bitmap bitmap, IProgressHandler progressHandler) { System.Drawing.Imaging.BitmapData bmpData; int numRows = raster.NumRows; int numColumns = raster.NumColumns; if (rasterSymbolizer == null) { throw new NullLogException("rasterSymbolizer"); } if (rasterSymbolizer.Scheme.Categories == null || rasterSymbolizer.Scheme.Categories.Count == 0) return; // Create a new Bitmap and use LockBits combined with Marshal.Copy to get an array of bytes to work with. Rectangle rect = new Rectangle(0, 0, numColumns, numRows); try { bmpData = bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); } catch { System.IO.MemoryStream ms = new System.IO.MemoryStream(); bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp); ms.Position = 0; bmpData = bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); } int numBytes = bmpData.Stride * bmpData.Height; byte[] rgbData = new byte[numBytes]; System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, rgbData, 0, numBytes); Color pixelColor; ProgressMeter pm = new ProgressMeter(progressHandler, MessageStrings.PaintingColorScheme, raster.NumRows); if (numRows * numColumns < 100000) pm.StepPercent = 50; if (numRows * numColumns < 500000) pm.StepPercent = 10; if (numRows * numColumns < 1000000) pm.StepPercent = 5; for (int row = 0; row < numRows; row++) { for (int col = 0; col < numColumns; col++) { // use the colorbreaks to calculate the colors pixelColor = rasterSymbolizer.GetColor(raster.Value[row, col]); // control transparency here int alpha = Convert.ToInt32(rasterSymbolizer.Opacity * 255); if (alpha > 255) alpha = 255; if (alpha < 0) alpha = 0; byte a = (byte)alpha; byte r = pixelColor.R; byte g = pixelColor.G; byte b = pixelColor.B; int offset = row * bmpData.Stride + col * 4; rgbData[offset] = b; rgbData[offset + 1] = g; rgbData[offset + 2] = r; rgbData[offset + 3] = a; } pm.CurrentValue = row; } pm.Reset(); if (rasterSymbolizer.IsSmoothed) { Smoother mySmoother = new Smoother(bmpData, rgbData, progressHandler); rgbData = mySmoother.Smooth(); } // Copy the values back into the bitmap System.Runtime.InteropServices.Marshal.Copy(rgbData, 0, bmpData.Scan0, numBytes); bitmap.UnlockBits(bmpData); rasterSymbolizer.ColorSchemeHasUpdated = true; return; }
/// <summary> /// Creates a new raster with the specified cell size. If the cell size /// is zero, this will default to the shorter of the width or height /// divided by 256. If the cell size produces a raster that is greater /// than 8,000 pixels in either dimension, it will be re-sized to /// create an 8,000 length or width raster. /// </summary> /// <param name="fs">The featureset to convert to a raster</param> /// <param name="cellSize">The double extent of the cell.</param> /// <param name="fieldName">The integer field index of the file.</param> /// <param name="destFilename">The filename of the raster to create</param> /// <param name="driverCode">The optional GDAL driver code to use if using GDAL /// for a format that is not discernable from the file extension. An empty string /// is usually perfectly acceptable here.</param> /// <param name="options">For GDAL rasters, they can be created with optional parameters /// passed in as a string array. In most cases an empty string is perfectly acceptable.</param> /// <param name="progressHandler">An interface for handling the progress messages.</param> /// <returns>Generates a raster from the vectors.</returns> public static IRaster ToRaster(IFeatureSet fs, ref double cellSize, string fieldName, string destFilename, string driverCode, string[] options, IProgressHandler progressHandler) { IEnvelope env = fs.Envelope; if(cellSize == 0) { if(fs.Envelope.Width < fs.Envelope.Height) { cellSize = env.Width/256; } else { cellSize = env.Height/256; } } int w = (int)Math.Ceiling(env.Width/cellSize); if (w > 8000) { w = 8000; cellSize = env.Width/8000; } int h = (int) Math.Ceiling(env.Height/cellSize); if (h > 8000) { cellSize = env.Height/8000; h = 8000; } Bitmap bmp = new Bitmap(w, h); Graphics g = Graphics.FromImage(bmp); g.Clear(Color.Transparent); g.SmoothingMode = SmoothingMode.None; g.TextRenderingHint = TextRenderingHint.SingleBitPerPixel; g.InterpolationMode = InterpolationMode.NearestNeighbor; Hashtable colorTable; MapArgs args = new MapArgs(new Rectangle(0, 0, w, h), env, g); switch (fs.FeatureType) { case FeatureTypes.Polygon: { MapPolygonLayer mpl = new MapPolygonLayer(fs); PolygonScheme ps = new PolygonScheme(); colorTable = ps.GenerateUniqueColors(fs, fieldName); mpl.Symbology = ps; mpl.DrawRegions(args, new List<IEnvelope> {env}); } break; case FeatureTypes.Line: { MapLineLayer mpl = new MapLineLayer(fs); LineScheme ps = new LineScheme(); colorTable = ps.GenerateUniqueColors(fs, fieldName); mpl.Symbology = ps; mpl.DrawRegions(args, new List<IEnvelope> { env }); } break; default: { MapPointLayer mpl = new MapPointLayer(fs); PointScheme ps = new PointScheme(); colorTable = ps.GenerateUniqueColors(fs, fieldName); mpl.Symbology = ps; mpl.DrawRegions(args, new List<IEnvelope> { env }); } break; } Type tp = fieldName == "FID" ? typeof(int) : fs.DataTable.Columns[fieldName].DataType; if (tp == typeof(string)) tp = typeof (double); // We will try to convert to double if it is a string Raster output = new Raster(); MWImageData image = new MWImageData(bmp, env); ProgressMeter pm = new ProgressMeter(progressHandler, "Converting To Raster Cells", h); output.CreateNew(destFilename, driverCode, w, h, 1, tp, options); output.Bounds = new RasterBounds(h, w, env); List<RcIndex> locations = new List<RcIndex>(); List<string> failureList = new List<string>(); for (int row = 0; row < h; row++) { for (int col = 0; col < w; col++) { Color c = image.GetColor(row, col); if (c.A == 0) { output.Value[row, col] = output.NoDataValue; } else { if (colorTable.ContainsKey(c) == false) { if (c.A < 125) { output.Value[row, col] = output.NoDataValue; continue; } // Use a color matching distance to pick the closest member object val = GetCellValue(w, h, row, col, image, c, colorTable, locations); output.Value[row, col] = GetDouble(val, failureList); } else { output.Value[row, col] = GetDouble(colorTable[c], failureList); } } } pm.CurrentValue = row; } const int maxIterations = 5; int iteration = 0; while(locations.Count > 0) { List<RcIndex> newLocations = new List<RcIndex>(); foreach (RcIndex location in locations) { object val = GetCellValue(w, h, location.Row, location.Column, image, image.GetColor(location.Row, location.Column), colorTable, newLocations); output.Value[location.Row, location.Column] = GetDouble(val, failureList); } locations = newLocations; iteration++; if(iteration > maxIterations) break; } pm.Reset(); return output; }
/// <summary> /// This creates a completely new raster from the windowed domain on the original raster. This new raster /// will have a separate source file, and values like NumRowsInFile will correspond to the newly created file. /// All the values will be copied to the new source file. If inRam = true and the new raster is small enough, /// the raster values will be loaded into memory. /// </summary> /// <param name="filename"></param> /// <param name="startRow">The 0 based integer index of the top row to copy from this raster. If this raster is itself a window, 0 represents the startRow from the file.</param> /// <param name="endRow">The integer index of the bottom row to copy from this raster. The largest allowed value is NumRows - 1.</param> /// <param name="startColumn">The 0 based integer index of the leftmost column to copy from this raster. If this raster is a window, 0 represents the startColumn from the file.</param> /// <param name="endColumn">The 0 based integer index of the rightmost column to copy from this raster. The largest allowed value is NumColumns - 1</param> /// <param name="copyValues">If this is true, the valeus are saved to the file. If this is false and the data can be loaded into Ram, no file handling is done. Otherwise, a file of NoData values is created.</param> /// <param name="inRam">Boolean. If this is true and the window is small enough, a copy of the values will be loaded into memory.</param> /// <returns>An implementation of IRaster</returns> public new IRaster CopyWindow(string filename, int startRow, int endRow, int startColumn, int endColumn, bool copyValues, bool inRam) { int numCols = endColumn - startColumn + 1; int numRows = endRow - startRow + 1; BinaryDoubleRaster result = new BinaryDoubleRaster(filename, numCols, numRows, inRam); result.Projection = Projection; // The affine coefficients defining the world file are the same except that they are translated over. Only the position of the // upper left corner changes. Everything else is the same as the previous raster. // X = [0] + [1] * column + [2] * row; // Y = [3] + [4] * column + [5] * row; result.Bounds = new RasterBounds(result.NumRows, result.NumColumns, new double[6]); result.Bounds.AffineCoefficients[0] = Bounds.AffineCoefficients[0] + Bounds.AffineCoefficients[1]*startColumn + Bounds.AffineCoefficients[2]*startRow; result.Bounds.AffineCoefficients[1] = Bounds.AffineCoefficients[1]; result.Bounds.AffineCoefficients[2] = Bounds.AffineCoefficients[2]; result.Bounds.AffineCoefficients[3] = Bounds.AffineCoefficients[3] + Bounds.AffineCoefficients[4]*startColumn + Bounds.AffineCoefficients[5]*startRow; result.Bounds.AffineCoefficients[4] = Bounds.AffineCoefficients[4]; result.Bounds.AffineCoefficients[5] = Bounds.AffineCoefficients[5]; if (IsInRam) { ProgressMeter pm = new ProgressMeter(ProgressHandler, MessageStrings.CopyingValues, numRows); // copy values directly using both data structures for (int row = 0; row < numRows; row++) { for (int col = 0; col < numCols; col++) { result.Data[row][col] = Data[startRow + row][startColumn + col]; } pm.CurrentValue = row; } pm.Reset(); if (result.IsInRam == false) { // Force the result raster to write itself to a file and then purge its memory. result.Write(filename); result.Data = null; } } else { if (result.IsInRam) { // the source is not in memory, so we just read the values from the file as if opening it directly from the file. result.OpenWindow(Filename, startRow, endRow, startColumn, endColumn, true); } else { // Both sources are file based so we basically copy rows of bytes from one to the other. FileStream source = new FileStream(Filename, FileMode.Open, FileAccess.Read, FileShare.Read); result.WriteHeader(filename); FileStream dest = new FileStream(filename, FileMode.Append, FileAccess.Write, FileShare.None); source.Seek(HeaderSize, SeekOrigin.Begin); BinaryReader bReader = new BinaryReader(source); BinaryWriter bWriter = new BinaryWriter(dest); ProgressMeter pm = new ProgressMeter(ProgressHandler, MessageStrings.CopyingValues, numRows); // copy values directly using both data structures source.Seek(NumColumnsInFile*startRow*ByteSize, SeekOrigin.Current); for (int row = 0; row < numRows; row++) { source.Seek(numCols*ByteSize, SeekOrigin.Current); byte[] rowData = bReader.ReadBytes(ByteSize*numCols); bWriter.Write(rowData); source.Seek(NumColumnsInFile - endColumn + 1, SeekOrigin.Current); bWriter.Flush(); pm.CurrentValue = row; } pm.Reset(); } } return result; }
/// <summary> /// This assumes that the base image has been written to the file. This will now attempt to calculate /// the down-sampled images. /// </summary> /// <param name="progressHandler"></param> public void CreatePyramids2(IProgressHandler progressHandler) { double count = _header.ImageHeaders[0].NumRows; ProgressMeter pm = new ProgressMeter(progressHandler, "Generating Pyramids", count); int prog = 0; for(int scale = 0; scale < _header.ImageHeaders.Length-1; scale++) { PyramidImageHeader ph = _header.ImageHeaders[scale]; int rows = ph.NumRows; int cols = ph.NumColumns; // Horizontal Blur Pass byte[] r1 = ReadWindow(0, 0, 1, cols, scale); byte[] r2 = ReadWindow(1, 0, 1, cols, scale); byte[] vals = Blur(null, r1, r2); vals = DownSample(vals); WriteWindow(vals, 0, 0, 1, cols/2, scale + 1); prog++; pm.CurrentValue = prog; byte[] r3 = ReadWindow(2, 0, 1, cols, scale); vals = Blur(r1, r2, r3); vals = DownSample(vals); WriteWindow(vals, 1, 0, 1, cols / 2, scale + 1); prog++; pm.CurrentValue = prog; for(int row = 3; row < rows -1; row++) { r1 = r2; r2 = r3; r3 = ReadWindow(row, 0, 1, cols, scale); prog++; pm.CurrentValue = prog; if (row % 2 == 1) continue; vals = Blur(r1, r2, r3); vals = DownSample(vals); WriteWindow(vals, row/2-1, 0, 1, cols/2, scale + 1); } if ((rows - 1)%2 == 0) { vals = Blur(r2, r3, r2); vals = DownSample(vals); WriteWindow(vals, rows / 2 - 1, 0, 1, cols / 2, scale + 1); } prog++; pm.CurrentValue = prog; } pm.Reset(); }
/// <summary> /// This creates a window from this raster. The window will still save to the same /// source file, but only has access to a small window of data, so it can be loaded like a buffer. /// The georeferenced extents will be for the new window, not the original raster. startRow and endRow /// will exist in the new raster, however, so that it knows how to copy values back to the original raster. /// </summary> /// <param name="startRow">The 0 based integer index of the top row to get from this raster. If this raster is itself a window, 0 represents the startRow from the file.</param> /// <param name="endRow">The integer index of the bottom row to get from this raster. The largest allowed value is NumRows - 1.</param> /// <param name="startColumn">The 0 based integer index of the leftmost column to get from this raster. If this raster is a window, 0 represents the startColumn from the file.</param> /// <param name="endColumn">The 0 based integer index of the rightmost column to get from this raster. The largest allowed value is NumColumns - 1</param> /// <param name="inRam">Boolean. If this is true and the window is small enough, a copy of the values will be loaded into memory.</param> /// <returns>An implementation of IRaster</returns> public new IRaster GetWindow(int startRow, int endRow, int startColumn, int endColumn, bool inRam) { int numCols = endColumn - startColumn + 1; int numRows = endRow - startRow + 1; BinaryDoubleRaster result = new BinaryDoubleRaster(); result.Filename = Filename; result.Projection = Projection; result.NumRows = endRow - startRow + 1; result.NumColumns = endColumn - startColumn + 1; result.NumRowsInFile = NumRowsInFile; result.NumColumnsInFile = NumColumnsInFile; result.NoDataValue = NoDataValue; result.StartColumn = startColumn + StartColumn; result.StartRow = startRow + StartRow; result.EndColumn = endColumn + StartColumn; result.EndRow = EndRow + StartRow; // Reposition the "raster" so that it matches the window, not the whole raster // X = [0] + [1] * column + [2] * row; // Y = [3] + [4] * column + [5] * row; result.Bounds = new RasterBounds(result.NumRows, result.NumColumns, new double[6]); result.Bounds.AffineCoefficients[0] = Bounds.AffineCoefficients[0] + Bounds.AffineCoefficients[1]*startColumn + Bounds.AffineCoefficients[2]*startRow; result.Bounds.AffineCoefficients[1] = Bounds.AffineCoefficients[1]; result.Bounds.AffineCoefficients[2] = Bounds.AffineCoefficients[2]; result.Bounds.AffineCoefficients[3] = Bounds.AffineCoefficients[3] + Bounds.AffineCoefficients[4]*startColumn + Bounds.AffineCoefficients[5]*startRow; result.Bounds.AffineCoefficients[4] = Bounds.AffineCoefficients[4]; result.Bounds.AffineCoefficients[5] = Bounds.AffineCoefficients[5]; // Now we can copy any values currently in memory. if (IsInRam) { //result.ReadHeader(Filename); result.Data = new double[numRows][]; ProgressMeter pm = new ProgressMeter(ProgressHandler, MessageStrings.CopyingValues, endRow); pm.StartValue = startRow; // copy values directly using both data structures for (int row = 0; row < numRows; row++) { result.Data[row] = new double[numCols]; for (int col = 0; col < numCols; col++) { result.Data[row][col] = Data[startRow + row][startColumn + col]; } pm.CurrentValue = row; } pm.Reset(); } else result.OpenWindow(Filename, startRow, endRow, startColumn, endColumn, inRam); result.Value = new DoubleValueGrid(result); return result; }
/// <summary> /// This tests each feature of the input /// </summary> /// <param name="self">This featureSet</param> /// <param name="other">The featureSet to perform intersection with</param> /// <param name="joinType">The attribute join type</param> /// <param name="progHandler">A progress handler for status messages</param> /// <returns>An IFeatureSet with the intersecting features, broken down based on the join Type</returns> public static IFeatureSet Intersection(this IFeatureSet self, IFeatureSet other, FieldJoinType joinType, IProgressHandler progHandler) { IFeatureSet result = null; ProgressMeter pm = new ProgressMeter(progHandler, "Calculating Intersection", self.Features.Count); if (joinType == FieldJoinType.All) { result = CombinedFields(self, other); // Intersection is symetric, so only consider I X J where J <= I int i=0; foreach(IFeature selfFeature in self.Features) { List<IFeature> potentialOthers = other.Select(selfFeature.Envelope); foreach (IFeature otherFeature in potentialOthers) { selfFeature.Intersection(otherFeature, result, joinType); } pm.CurrentValue = i; i++; } pm.Reset(); } if (joinType == FieldJoinType.LocalOnly) { result = new FeatureSet(); result.CopyTableSchema(self); result.FeatureType = self.FeatureType; IFeature union; pm = new ProgressMeter(progHandler, "Calculating Union", other.Features.Count); if(other.Features != null && other.Features.Count > 0) { union = other.Features[0]; for(int i = 1; i < other.Features.Count; i++) { union = union.Union(other.Features[i]); pm.CurrentValue = i; } pm.Reset(); pm = new ProgressMeter(progHandler, "Calculating Intersections", self.NumRows()); Extent otherEnvelope = new Extent(union.Envelope); for (int shp = 0; shp < self.ShapeIndices.Count; shp++) { if (!self.ShapeIndices[shp].Extent.Intersects(otherEnvelope)) continue; IFeature selfFeature = self.GetFeature(shp); selfFeature.Intersection(union, result, joinType); pm.CurrentValue = shp; } pm.Reset(); } } if (joinType == FieldJoinType.ForeignOnly) { result = new FeatureSet(); result.CopyTableSchema(other); IFeature union; if (self.Features != null && self.Features.Count > 0) { pm = new ProgressMeter(progHandler, "Calculating Union", self.Features.Count); union = self.Features[0]; for (int i = 1; i < self.Features.Count; i++) { union = union.Union(self.Features[i]); pm.CurrentValue = i; } pm.Reset(); if (other.Features != null) { pm = new ProgressMeter(progHandler, "Calculating Intersection", other.Features.Count); int j = 0; foreach (IFeature otherFeature in other.Features) { IFeature test = otherFeature.Intersection(union, result, joinType); if (test.BasicGeometry != null) { result.Features.Add(test); } pm.CurrentValue = j; j++; } } pm.Reset(); } } return result; }
/// <summary> /// This will resample the cells. /// If the cell size is zero, this will default to the shorter of the width or height /// divided by 256. /// </summary> /// <param name="input1">Input Raster.</param> /// <param name="cellHeight">New Cell Height or Null.</param> /// <param name="cellWidth">New Cell Width or Null.</param> /// <param name="destFilename">Output Raster Name.</param> /// <param name="progressHandler">An interface for handling the progress messages.</param> /// <returns>Resampled raster.</returns> public static IRaster ReSample(IRaster input1,double cellHeight, double cellWidth, string destFilename, IProgressHandler progressHandler) { if (input1 == null) return null; IEnvelope envelope = input1.Bounds.Envelope; if (cellHeight == 0) { cellHeight = envelope.Height / 256; } if(cellWidth==0) { cellWidth = envelope.Width / 256; } //Calculate new number of columns and rows int noOfCol = Convert.ToInt32(Math.Abs(envelope.Width / cellWidth)); int noOfRow = Convert.ToInt32(Math.Abs(envelope.Height / cellHeight)); IRaster output = Raster.Create(destFilename, "", noOfCol, noOfRow, 1, input1.DataType, new[] { "" }); RasterBounds bound = new RasterBounds(noOfRow, noOfCol, envelope); output.Bounds = bound; output.NoDataValue = input1.NoDataValue; RcIndex index1; int max = (output.Bounds.NumRows); ProgressMeter pm = new ProgressMeter(progressHandler, "ReSize Cells", max); //Loop throug every cell for new value for (int i = 0; i < max; i++) { for (int j = 0; j < output.Bounds.NumColumns; j++) { //Projet the cell position to Map Coordinate cellCenter = output.CellToProj(i, j); index1 = input1.ProjToCell(cellCenter); double val; if (index1.Row <= input1.EndRow && index1.Column <= input1.EndColumn && index1.Row > -1 && index1.Column > -1) { if (input1.Value[index1.Row, index1.Column] == input1.NoDataValue) val = output.NoDataValue; else val = input1.Value[index1.Row, index1.Column]; } else val = output.NoDataValue; output.Value[i, j] = val; } pm.CurrentPercent = i; } output.Save(); pm.Reset(); return output; }