/* * Copyright (c) 2003-2012 Fred Hutchinson Cancer Research Center * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.fhcrc.cpl.viewer.gui; import javax.media.j3d.QuadArray; import javax.media.j3d.Shape3D; import javax.media.j3d.Appearance; import javax.vecmath.Point3f; import javax.vecmath.Vector3f; import javax.vecmath.Color3f; /** * User: mbellew * Date: Feb 12, 2005 * Time: 9:52:40 AM */ public class Surface { Shape3D _shape; static int[] topoRGB = { 0x4C00FF, 0x4900FF, 0x4500FF, 0x4200FF, 0x3E00FF, 0x3B00FF, 0x3700FF, 0x3300FF, 0x3000FF, 0x2C00FF, 0x2800FF, 0x2500FF, 0x2100FF, 0x1E00FF, 0x1A00FF, 0x1600FF, 0x1300FF, 0x0F00FF, 0x0C00FF, 0x0800FF, 0x0400FF, 0x0100FF, 0x0003FF, 0x0006FF, 0x000AFF, 0x000DFF, 0x0011FF, 0x0015FF, 0x0018FF, 0x001CFF, 0x001FFF, 0x0023FF, 0x0027FF, 0x002AFF, 0x002EFF, 0x0031FF, 0x0035FF, 0x0039FF, 0x003CFF, 0x0040FF, 0x0043FF, 0x0047FF, 0x004BFF, 0x004EFF, 0x0052FF, 0x0055FF, 0x0059FF, 0x005DFF, 0x0060FF, 0x0064FF, 0x0067FF, 0x006BFF, 0x006FFF, 0x0072FF, 0x0076FF, 0x007AFF, 0x007DFF, 0x0081FF, 0x0084FF, 0x0088FF, 0x008BFF, 0x008FFF, 0x0093FF, 0x0096FF, 0x009AFF, 0x009EFF, 0x00A1FF, 0x00A5FF, 0x00A8FF, 0x00ACFF, 0x00AFFF, 0x00B3FF, 0x00B7FF, 0x00BAFF, 0x00BEFF, 0x00C1FF, 0x00C5FF, 0x00C9FF, 0x00CCFF, 0x00D0FF, 0x00D3FF, 0x00D7FF, 0x00DBFF, 0x00DEFF, 0x00E2FF, 0x00E5FF, 0x00FF4D, 0x00FF49, 0x00FF45, 0x00FF42, 0x00FF3E, 0x00FF3A, 0x00FF37, 0x00FF33, 0x00FF2F, 0x00FF2C, 0x00FF28, 0x00FF24, 0x00FF21, 0x00FF1D, 0x00FF1A, 0x00FF16, 0x00FF12, 0x00FF0F, 0x00FF0B, 0x00FF07, 0x00FF04, 0x00FF00, 0x04FF00, 0x07FF00, 0x0BFF00, 0x0FFF00, 0x12FF00, 0x16FF00, 0x1AFF00, 0x1DFF00, 0x21FF00, 0x24FF00, 0x28FF00, 0x2CFF00, 0x2FFF00, 0x33FF00, 0x37FF00, 0x3AFF00, 0x3EFF00, 0x42FF00, 0x45FF00, 0x49FF00, 0x4DFF00, 0x50FF00, 0x54FF00, 0x57FF00, 0x5BFF00, 0x5FFF00, 0x62FF00, 0x66FF00, 0x6AFF00, 0x6DFF00, 0x71FF00, 0x75FF00, 0x78FF00, 0x7CFF00, 0x80FF00, 0x83FF00, 0x87FF00, 0x8AFF00, 0x8EFF00, 0x92FF00, 0x95FF00, 0x99FF00, 0x9DFF00, 0xA0FF00, 0xA4FF00, 0xA8FF00, 0xABFF00, 0xAFFF00, 0xB3FF00, 0xB6FF00, 0xBAFF00, 0xBDFF00, 0xC1FF00, 0xC5FF00, 0xC8FF00, 0xCCFF00, 0xD0FF00, 0xD3FF00, 0xD7FF00, 0xDBFF00, 0xDEFF00, 0xE2FF00, 0xE6FF00, 0xFFFF00, 0xFFFE02, 0xFFFD04, 0xFFFB06, 0xFFFA08, 0xFFF90B, 0xFFF80D, 0xFFF70F, 0xFFF611, 0xFFF513, 0xFFF415, 0xFFF317, 0xFFF219, 0xFFF11C, 0xFFF01E, 0xFFEF20, 0xFFEE22, 0xFFED24, 0xFFEC26, 0xFFEC28, 0xFFEB2A, 0xFFEA2D, 0xFFE92F, 0xFFE831, 0xFFE833, 0xFFE735, 0xFFE637, 0xFFE639, 0xFFE53C, 0xFFE43E, 0xFFE440, 0xFFE342, 0xFFE344, 0xFFE246, 0xFFE148, 0xFFE14A, 0xFFE04D, 0xFFE04F, 0xFFDF51, 0xFFDF53, 0xFFDF55, 0xFFDE57, 0xFFDE59, 0xFFDD5B, 0xFFDD5E, 0xFFDD60, 0xFFDD62, 0xFFDC64, 0xFFDC66, 0xFFDC68, 0xFFDC6A, 0xFFDB6C, 0xFFDB6F, 0xFFDB71, 0xFFDB73, 0xFFDB75, 0xFFDB77, 0xFFDB79, 0xFFDB7B, 0xFFDB7D, 0xFFDB80, 0xFFDB82, 0xFFDB84, 0xFFDB86, 0xFFDB88, 0xFFDB8A, 0xFFDB8C, 0xFFDB8E, 0xFFDB90, 0xFFDB93, 0xFFDC95, 0xFFDC97, 0xFFDC99, 0xFFDC9B, 0xFFDD9D, 0xFFDD9F, 0xFFDDA1, 0xFFDDA4, 0xFFDEA6, 0xFFDEA8, 0xFFDFAA, 0xFFDFAC, 0xFFDFAE, 0xFFE0B0, 0xFFE0B2}; static float[][] colorMap = new float[topoRGB.length][]; static { for (int i=0 ; i<topoRGB.length ; i++) { int c = topoRGB[i]; float r = (0xff & (c>>16)) / 255F; float g = (0xff & (c>>8)) / 255F; float b = (0xff & (c)) / 255F; colorMap[i] = new float[] {r,g,b}; } } float scaleX(float x, float width) { return x/width - .5F; } float scaleY(float y, float height) { return y/height - .5F; } float scaleZ(float z, float max) { return z/max; } public Surface(float[][] m, Appearance appearance) { // compute vertices int width = m.length; int height = m[0].length; float maxZ = 1; for (int x = 0; x < width; x++) for (int y = 0; y < height; y++) maxZ = Math.max(maxZ, m[x][y]); // compute a 3d point for each point in the matrix Point3f[][] points = new Point3f[width][height]; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { points[x][y] = new Point3f( scaleX(x,width), scaleY(y,height), scaleZ(m[x][y],maxZ)); } } Vector3f[][] vectors = new Vector3f[width][height]; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { Point3f x1 = x>0 ? points[x-1][y] : points[x][y]; Point3f x2 = x<width-1 ? points[x+1][y] : points[x][y]; Point3f y1 = y>0 ? points[x][y-1] : points[x][y]; Point3f y2 = y<height-1 ? points[x][y+1] : points[x][y]; float dzX = x2.z - x1.z; if (x>0 && x<width-1) dzX /= 2; float dzY = y2.z - y1.z; if (y>0 && y<height-1) dzY /= 2; // a = (1, 0, dzX) // b = (0, 1, dzY) // n.x = a.y * b.z - a.z * b.y = -a.z // n.y = a.z * b.x - a.x * b.z = -b.z // n.z = a.x * b.y - a.y * b.x = 1 float nX = -dzX; float nY = -dzY; float nZ = 1; double nLen = Math.sqrt(nX*nX+nY*nY+1); nX /= nLen; nY /= nLen; nZ /= nLen; vectors[x][y] = new Vector3f((float)(nX/nLen), (float)(nY/nLen), (float)(nZ/nLen)); } } Color3f[][] colors = new Color3f[width][height]; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { double z = points[x][y].z; // z = Math.log1p(z) / Math.log1p(1); // z = Math.max(0F,Math.min(1F,z)); // colors[x][y] = new Color3f((float)z,(float)z,(float)z); z = (float)(Math.log(z+1000)/Math.log(1001) * (colors.length-2)); z = Math.max(0, Math.min(z, colorMap.length-2)); int i = (int)Math.floor(z); double r = z-i; colors[x][y] = new Color3f( (float)(colorMap[i][0] * (1-r) + colorMap[i+1][0] * r), (float)(colorMap[i][1] * (1-r) + colorMap[i+1][1] * r), (float)(colorMap[i][2] * (1-r) + colorMap[i+1][2] * r)); } } Point3f[] verts = new Point3f[4 * (width-1) * (height-1)]; Vector3f[] normals = new Vector3f[4 * (width-1) * (height-1)]; Color3f[] clrs = new Color3f[4 * (width-1) * (height-1)]; int v = 0, n=0, c=0; for (int x = 0; x < width - 1; x++) { for (int y = 0; y < height - 1; y++) { verts[v++] = points[x][y]; verts[v++] = points[x + 1][y]; verts[v++] = points[x + 1][y + 1]; verts[v++] = points[x][y + 1]; normals[n++] = vectors[x][y]; normals[n++] = vectors[x+1][y+1]; normals[n++] = vectors[x+1][y]; normals[n++] = vectors[x][y+1]; clrs[c++] = colors[x][y]; clrs[c++] = colors[x+1][y]; clrs[c++] = colors[x+1][y+1]; clrs[c++] = colors[x][y+1]; } } QuadArray quad = new QuadArray(verts.length, QuadArray.COORDINATES|QuadArray.NORMALS|QuadArray.COLOR_3); quad.setCoordinates(0, verts); quad.setNormals(0, normals); quad.setColors(0, clrs); _shape = new Shape3D(quad, appearance); } public Shape3D getShape() { return _shape; } }