/* * GridShadeOperator.java * * Created on January 28, 2006, 6:28 PM * */ package ika.geo.grid; import ika.geo.*; import ika.utils.ImageUtils; import java.awt.image.BufferedImage; /** * * @author Bernhard Jenny, Institute of Cartography, ETH Zurich */ public class GridShadeOperator implements GridOperator { private double elevation = 25; private double azimuth = 315; private double LIGHT_AMBIENT = 0.4; private double LIGHT_DIFFUSE = 0.6; /** Creates a new instance of GridShadeOperator */ public GridShadeOperator() { } public String getName() { return "Grid Shade"; } public GeoGrid operate(GeoGrid geoGrid) { if (geoGrid == null) { throw new IllegalArgumentException(); } final int newCols = Math.max(2, geoGrid.getCols() - 1); final int newRows = Math.max(2, geoGrid.getRows() - 1); final double meshSize = geoGrid.getCellSize(); GeoGrid newGrid = new GeoGrid(newCols, newRows, meshSize); newGrid.setWest(geoGrid.getWest() + meshSize); newGrid.setNorth(geoGrid.getNorth() + meshSize); if (newCols <= 2 || newRows <= 2) { return newGrid; } float[][] srcGrid = geoGrid.getGrid(); float[][] dstGrid = newGrid.getGrid(); final int srcRows = geoGrid.getRows(); final int srcCols = geoGrid.getCols(); // compute normalized light vector for azimuth and zenith final double alpha = Math.toRadians(90 - this.azimuth); final double zenith = Math.toRadians(90 - this.elevation); final double sinz = Math.sin(zenith); final double luxX = (float) (Math.cos(alpha) * sinz); final double luxY = (float) (Math.sin(alpha) * sinz); final double luxZ = (float) Math.cos(zenith); for (int row = 0; row < srcRows - 1; row++) { float[] dstRow = dstGrid[row]; for (int col = 0; col < srcCols - 1; col++) { // two diagonal vectors final float d1 = srcGrid[row + 1][col + 1] - srcGrid[row][col]; final float d2 = srcGrid[row][col + 1] - srcGrid[row + 1][col]; double nx = d2 - d1; double ny = -d1 - d2; double nz = 2. * meshSize; // normalize vector final double lengthInv = Math.sqrt(nx*nx + ny*ny + nz*nz); nx /= lengthInv; ny /= lengthInv; nz /= lengthInv; // scalar product of light and normal vector final double cosa = luxX * nx + luxY * ny + luxZ * nz; if (cosa > 0.) dstRow[col] = (float)(cosa) * 255.f; } } return newGrid; } public ika.geo.GeoImage operateToImage(ika.geo.GeoGrid geoGrid) { return phongShading(geoGrid); /* if (geoGrid == null) throw new IllegalArgumentException(); final int imgCols = Math.max(2, geoGrid.getCols() - 1); final int imgRows = Math.max(2, geoGrid.getRows() - 1); final double meshSize = geoGrid.getCellSize(); if (imgCols <= 2 || imgRows <= 2) return null; float[][] srcGrid = geoGrid.getGrid(); final int srcRows = geoGrid.getRows(); final int srcCols = geoGrid.getCols(); // compute normalized light vector for azimuth and zenith final double alpha = Math.toRadians(90 - this.azimuth); final double zenith = Math.toRadians(90 - this.elevation); final double sinz = Math.sin(zenith); final double luxX = (float) (Math.cos(alpha) * sinz); final double luxY = (float) (-Math.sin(alpha) * sinz); final double luxZ = (float) Math.cos(zenith); short[] gray = new short[imgCols * imgRows]; int grayID = 0; for (int row = 0; row < srcRows - 1; row++) { for (int col = 0; col < srcCols - 1; col++) { // two diagonal vectors final float d1 = srcGrid[row + 1][col + 1] - srcGrid[row][col]; final float d2 = srcGrid[row][col + 1] - srcGrid[row + 1][col]; double nx = d2 - d1; double ny = -d1 - d2; double nz = 2. * meshSize; // normalize vector final double lengthInv = Math.sqrt(nx*nx + ny*ny + nz*nz); nx /= lengthInv; ny /= lengthInv; nz /= lengthInv; // scalar product of light and normal vector final double cosa = luxX * nx + luxY * ny + luxZ * nz; if (cosa < 0.) gray[grayID] = 0; else if (cosa > 1.) gray[grayID] = 255; else gray[grayID] = (short)(cosa * 255); ++grayID; } } BufferedImage image = ImageUtils.createGrayscaleImage(imgCols, imgRows, 8, gray); GeoImage newImage = new GeoImage(image, imgCols, imgRows, meshSize); newImage.setWest(geoGrid.getWest()); newImage.setNorth(geoGrid.getNorth()); return newImage;*/ } public ika.geo.GeoImage phongShading(ika.geo.GeoGrid geoGrid) { if (geoGrid == null) { throw new IllegalArgumentException(); } final int imgCols = Math.max(2, geoGrid.getCols() - 3); final int imgRows = Math.max(2, geoGrid.getRows() - 3); final double d = geoGrid.getCellSize(); final double d2 = 2 * d; if (imgCols <= 2 || imgRows <= 2) { return null; } float[][] srcGrid = geoGrid.getGrid(); final int srcRows = geoGrid.getRows(); final int srcCols = geoGrid.getCols(); // compute normalized light vector for azimuth and zenith final double alpha = Math.toRadians(90 - this.azimuth); final double zenith = Math.toRadians(90 - this.elevation); final double sinz = Math.sin(zenith); final double luxX = Math.cos(alpha) * sinz; final double luxY = Math.sin(alpha) * sinz; final double luxZ = Math.cos(zenith); byte[] gray = new byte[imgCols * imgRows]; int grayID = 0; for (int row = 1; row < srcRows - 2; row++) { for (int col = 1; col < srcCols - 2; col++) { final float v01 = srcGrid[row - 1][col]; final float v02 = srcGrid[row - 1][col + 1]; final float v10 = srcGrid[row][col - 1]; final float v11 = srcGrid[row][col]; final float v12 = srcGrid[row][col + 1]; final float v13 = srcGrid[row][col + 2]; final float v20 = srcGrid[row + 1][col - 1]; final float v21 = srcGrid[row + 1][col]; final float v22 = srcGrid[row + 1][col + 1]; final float v23 = srcGrid[row + 1][col + 2]; final float v31 = srcGrid[row + 2][col]; final float v32 = srcGrid[row + 2][col + 1]; // top left vector double xtl = v10 - v12; double ytl = v21 - v01; double ztl = d2; double l = Math.sqrt(xtl*xtl + ytl*ytl + ztl*ztl); xtl /= l; ytl /= l; ztl /= l; // top right vector double xtr = v11 - v13; double ytr = v22 - v02; double ztr = d2; l = Math.sqrt(xtr*xtr + ytr*ytr + ztr*ztr); xtr /= l; ytr /= l; ztr /= l; // bottom left vector double xbl = v20 - v22; double ybl = v31 - v11; double zbl = d2; l = Math.sqrt(xbl*xbl + ybl*ybl + zbl*zbl); xbl /= l; ybl /= l; zbl /= l; // bottom right vector double xbr = v21 - v23; double ybr = v32 - v12; double zbr = d2; l = Math.sqrt(xbr*xbr + ybr*ybr + zbr*zbr); xbr /= l; ybr /= l; zbr /= l; // sum of four vectors final double nx = (xtl + xtr + xbl + xbr) * 0.25; final double ny = (ytl + ytr + ybl + ybr) * 0.25; final double nz = (ztl + ztr + zbl + zbr) * 0.25; // scalar product of light and normal vector final double cosa = luxX * nx + luxY * ny + luxZ * nz; final double b = cosa > 0. ? cosa * LIGHT_DIFFUSE + LIGHT_AMBIENT : LIGHT_AMBIENT; /*if (b < 0.) gray[grayID] = 0; else if (b > 1.) gray[grayID] = 255; else*/ gray[grayID] = (byte) (((short) (b * 255)) & 0xFF); ++grayID; } } BufferedImage image = ImageUtils.createGrayscaleImage(imgCols, imgRows, gray); GeoImage newImage = new GeoImage(image, imgCols, imgRows, d); newImage.setWest(geoGrid.getWest()); newImage.setNorth(geoGrid.getNorth()); return newImage; } }