Select to view content in your preferred language

Bug when saving rasters?

442
1
10-06-2022 09:20 AM
PeterVanSchevensteen
New Contributor II

I am making an ArcGIS Pro add-in, and one of its features is that you can click on a raster and it will show you what the raster would look like if the water levels would rise to that clicked point. So basically it creates a new raster in which the elevations higher than the clicked point are preserved, and elevations lower are flattened to the clicked point. The new raster is then saved to the default geodatabase. Everything works like a charm and the result is as expected. However, if afterwards I refresh my map, or I reload the project, I see that the original raster has also changed. The source code never changes the original raster. Is this a bug or am I doing something wrong?

Here is my source code:

// lastClickedPoint is set in the tool like so:

protected override async Task<bool> OnSketchCompleteAsync(Geometry geometry)
{
try
{
 ElevationModule.lastClickedPoint = geometry as MapPoint;
return await base.OnSketchCompleteAsync(geometry);
}
catch (Exception ex) { ex.Show(); }
return await base.OnSketchCompleteAsync(geometry);
}

 

//In ElevationModule

 public static MapPoint lastClickedPoint;


public ICommand ExportCommand =>
exportCommand ?? (exportCommand = new RelayCommand(async () =>
{

try
{
MapView mapView = MapView.Active;
if (mapView == null || lastClickedPoint == null)
return;

await QueuedTask.Run(() =>
{
// Process the click in the topmost visible rasterlayer that extends around the clicked point
RasterLayer rasterLayer = mapView.Map.Layers.OfType<RasterLayer>()
.Where(rl => rl.IsVisible && lastClickedPoint.Extent.Intersects(rl.QueryExtent()))
.FirstOrDefault();

// Get the cell value of the clicked cell
Raster raster = rasterLayer.GetRaster();
Tuple<int, int> pixelCoordinates = raster.MapToPixel(lastClickedPoint.X, lastClickedPoint.Y);
object cellValue = raster.GetPixelValue(0, pixelCoordinates.Item1, pixelCoordinates.Item2);
float cellValueAsFloat = (float?)cellValue ?? 0;

//Calculate the new raster
Raster newRaster = Rasters.CalculateNewRaster(raster, cellValue);

// Save the new raster
Uri defaultGeodatabasePath = new Uri(Project.Current.DefaultGeodatabasePath);
Geodatabase defaultGeodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(defaultGeodatabasePath));
string newRasterDatasetName = "Result";
var newDataset = newRaster.SaveAs(newRasterDatasetName, defaultGeodatabase, "GDB");

// Make sure the new raster is shown in both the Catalog and the Contents pane
Project.Current.GetItems<GDBProjectItem>().FirstOrDefault(gdb => gdb.Path == Project.Current.DefaultGeodatabasePath).Refresh();
LayerFactory.Instance.CreateLayer(new Uri(Project.Current.DefaultGeodatabasePath + "\\" + newRasterDatasetName), mapView.Map, 0);
});
}
catch (Exception ex) { throw new ApplicationException("Issue exporting Raster Lower Value operation results.", ex); }

}));

 

public static Raster CalculateNewRaster(Raster raster, object cutoffValue)
{
try
{
RasterDataset rasterDataSet = (RasterDataset)raster.GetRasterDataset();
Raster newRaster = rasterDataSet.CreateRaster(new int[] { 0 });

int rasterHeight = raster.GetHeight(), rasterWidth = raster.GetWidth();

// Create the raster cursors of max 100x1000 using the height and width of the raster.
RasterCursor rasterCursor = raster.CreateCursor(Math.Min(rasterWidth, 1000), Math.Min(rasterHeight, 1000));
RasterCursor newRasterCursor = newRaster.CreateCursor(Math.Min(rasterWidth, 1000), Math.Min(rasterHeight, 1000));

// Use a do while loop to iterate through the pixel blocks of the raster using the raster cursor.
do
{
PixelBlock currentPixelBlock = rasterCursor.Current;
PixelBlock currentNewPixelBlock = newRasterCursor.Current;

int currentRasterHeight = currentPixelBlock.GetHeight(),
currentRasterWidth = currentPixelBlock.GetWidth();

Tuple<int, int> cursorTopLeft = rasterCursor.GetTopLeft();
raster.Read(cursorTopLeft.Item1, cursorTopLeft.Item2, currentPixelBlock);
newRaster.Read(cursorTopLeft.Item1, cursorTopLeft.Item2, currentNewPixelBlock);

Array pixelArray = currentPixelBlock.GetPixelData(0, true);
Array newPixelArray = currentNewPixelBlock.GetPixelData(0, true);
RasterPixelType rasterPixelType = currentPixelBlock.GetPixelType(0);

int colOffset = 0; // = i of row 0 of the current column
for (int column = 0; column < currentRasterWidth / 4; column++)
{
for (int row = 0; row < currentRasterHeight; row++)
{
object pixelValue = pixelArray.GetValue(column, row);
if ((float)pixelValue >= (float)cutoffValue)
newPixelArray.SetValue(pixelValue, column, row);
else
newPixelArray.SetValue(cutoffValue, column, row);
}
colOffset += currentRasterHeight;
}

currentNewPixelBlock.SetPixelData(0, newPixelArray);
newRaster.Write(cursorTopLeft.Item1, cursorTopLeft.Item2, currentNewPixelBlock);
newRasterCursor.MoveNext();
}
while (rasterCursor.MoveNext());
return newRaster;
}
catch (Exception ex) { throw new ApplicationException("Issue creating raster from clicked cell's value.", ex); }
}

Tags (3)
0 Kudos
1 Reply
GKmieliauskas
Esri Regular Contributor

Hi,

Your code works fine with ArcGIS  Pro 2.9.2 and source raster in tiff. I have changed one line (removed dividing by 4) from:

for (int column = 0; column < currentRasterWidth / 4; column++)

to:

for (int column = 0; column < currentRasterWidth; column++)

 

0 Kudos