001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2025 005 * Space Science and Engineering Center (SSEC) 006 * University of Wisconsin - Madison 007 * 1225 W. Dayton Street, Madison, WI 53706, USA 008 * https://www.ssec.wisc.edu/mcidas/ 009 * 010 * All Rights Reserved 011 * 012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and 013 * some McIDAS-V source code is based on IDV and VisAD source code. 014 * 015 * McIDAS-V is free software; you can redistribute it and/or modify 016 * it under the terms of the GNU Lesser Public License as published by 017 * the Free Software Foundation; either version 3 of the License, or 018 * (at your option) any later version. 019 * 020 * McIDAS-V is distributed in the hope that it will be useful, 021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 023 * GNU Lesser Public License for more details. 024 * 025 * You should have received a copy of the GNU Lesser Public License 026 * along with this program. If not, see https://www.gnu.org/licenses/. 027 */ 028 029package edu.wisc.ssec.mcidasv.data.hydra; 030 031import java.rmi.RemoteException; 032import java.util.ArrayList; 033import java.util.HashMap; 034import java.util.Map; 035 036import visad.FlatField; 037import visad.FunctionType; 038import visad.Gridded1DSet; 039import visad.QuickSort; 040import visad.RealTuple; 041import visad.RealTupleType; 042import visad.SampledSet; 043import visad.VisADException; 044 045public class MultiSpectralAggr extends MultiSpectralData { 046 047 Gridded1DSet aggrDomain = null; 048 049 MultiSpectralData[] adapters = null; 050 051 int[] sort_indexes = null; 052 053 float[] aggrValues = null; 054 055 float[] aggrSamples = null; 056 057 int numAdapters; 058 059 int numBands; 060 061 int[] offset; 062 063 public MultiSpectralAggr(MultiSpectralData[] adapters) 064 throws Exception { 065 super(adapters[0].swathAdapter, null); 066 this.adapters = adapters; 067 paramName = adapters[0].getParameter(); 068 069 numAdapters = adapters.length; 070 int[] numBandsAdapter = new int[numAdapters]; 071 offset = new int[numAdapters]; 072 SampledSet[] spectrumDomains = new SampledSet[numAdapters]; 073 074 if (adapters[0].spectrumAdapter.hasBandNames()) { 075 hasBandNames = true; 076 bandNameList = new ArrayList<>(); 077 bandNameMap = new HashMap<>(); 078 for (int k=0; k<numAdapters; k++) { 079 bandNameList.addAll(adapters[k].spectrumAdapter.getBandNames()); 080 bandNameMap.putAll(adapters[k].spectrumAdapter.getBandNameMap()); 081 } 082 } 083 084 numBands = 0; 085 for (int k=0; k<numAdapters; k++) { 086 SampledSet set = adapters[k].spectrumAdapter.getDomainSet(); 087 spectrumDomains[k] = set; 088 numBandsAdapter[k] = set.getLength(); 089 offset[k] = numBands; 090 numBands += numBandsAdapter[k]; 091 } 092 093 aggrSamples = new float[numBands]; 094 aggrValues = new float[numBands]; 095 096 for (int k=0; k<numAdapters; k++) { 097 float[][] samples = spectrumDomains[k].getSamples(false); 098 System.arraycopy(samples[0], 0, aggrSamples, offset[k], samples[0].length); 099 } 100 101 sort_indexes = QuickSort.sort(aggrSamples); 102 SpectrumAdapter specAdapt = adapters[0].spectrumAdapter; 103 aggrDomain = new Gridded1DSet(specAdapt.getDomainSet().getType(), 104 new float[][] {aggrSamples}, aggrSamples.length); 105 106 init_wavenumber = getWavenumberFromChannelIndex(0); 107 } 108 109 public FlatField getSpectrum(int[] coords) throws Exception { 110 FlatField spectrum = null; 111 for (int k=0; k<numAdapters; k++) { 112 spectrum = adapters[k].getSpectrum(coords); 113 if (spectrum == null) { 114 return null; 115 } 116 float[][] values = spectrum.getFloats(false); 117 System.arraycopy(values[0], 0, aggrValues, offset[k], values[0].length); 118 } 119 120 for (int t=0; t<numBands; t++) { 121 aggrValues[t] = aggrValues[sort_indexes[t]]; 122 } 123 124 spectrum = new FlatField((FunctionType)spectrum.getType(), aggrDomain); 125 spectrum.setSamples(new float[][] {aggrValues}); 126 127 return spectrum; 128 } 129 130 public FlatField getSpectrum(RealTuple location) throws Exception { 131 FlatField spectrum = null; 132 for (int k=0; k<numAdapters; k++) { 133 spectrum = adapters[k].getSpectrum(location); 134 if (spectrum == null) { 135 return null; 136 } 137 float[][] values = spectrum.getFloats(false); 138 System.arraycopy(values[0], 0, aggrValues, offset[k], values[0].length); 139 } 140 141 for (int t=0; t<numBands; t++) { 142 aggrValues[t] = aggrValues[sort_indexes[t]]; 143 } 144 145 spectrum = new FlatField((FunctionType)spectrum.getType(), aggrDomain); 146 spectrum.setSamples(new float[][] {aggrValues}); 147 148 return spectrum; 149 } 150 151 public FlatField getImage(Map<String, double[]> subset) throws Exception { 152 int channelIndex = (int) ((double[])subset.get(SpectrumAdapter.channelIndex_name))[0]; 153 154 int idx = sort_indexes[channelIndex]; 155 156 int swathAdapterIndex = numAdapters-1; 157 for (int k=0; k<numAdapters-1;k++) { 158 if (idx >= offset[k] && idx < offset[k+1]) swathAdapterIndex = k; 159 } 160 float channel = aggrSamples[channelIndex]; 161 FlatField image = adapters[swathAdapterIndex].getImage(channel, subset); 162 cs = ((RealTupleType) ((FunctionType)image.getType()).getDomain()).getCoordinateSystem(); 163 for (int k=0; k<numAdapters;k++) { 164 if (k != swathAdapterIndex) adapters[k].setCoordinateSystem(cs); 165 } 166 return image; 167 } 168 169 public FlatField getImage(float channel, Map<String, double[]> subset) throws Exception { 170 int channelIndex = aggrDomain.valueToIndex(new float[][] {{channel}})[0]; 171 // If a value is NaN, ^^ this returns -1 but that bricks the system 172 // a way to handle this is to assign a default value. For now 173 // this is set to the median value from the list 174 175 // McIDAS Inquiry #2780-3141 176 if (channelIndex == -1) channelIndex = sort_indexes.length >> 1; 177 178 int idx = sort_indexes[channelIndex]; 179 180 int swathAdapterIndex = numAdapters-1; 181 for (int k=0; k<numAdapters-1;k++) { 182 if (idx >= offset[k] && idx < offset[k+1]) swathAdapterIndex = k; 183 } 184 channel = aggrSamples[channelIndex]; 185 FlatField image = adapters[swathAdapterIndex].getImage(channel, subset); 186 cs = ((RealTupleType) ((FunctionType)image.getType()).getDomain()).getCoordinateSystem(); 187 for (int k=0; k<numAdapters;k++) { 188 if (k != swathAdapterIndex) adapters[k].setCoordinateSystem(cs); 189 } 190 return image; 191 } 192 193 public int getChannelIndexFromWavenumber(float channel) throws VisADException, RemoteException { 194 int idx = (aggrDomain.valueToIndex(new float[][] {{channel}}))[0]; 195 return idx; 196 } 197 198 public float getWavenumberFromChannelIndex(int index) throws Exception { 199 return (aggrDomain.indexToValue(new int[] {index}))[0][0]; 200 } 201 202 public Map<String, double[]> getDefaultSubset() { 203 Map<String, double[]> subset = adapters[0].getDefaultSubset(); 204 double chanIdx = 0; 205 try { 206 chanIdx = getChannelIndexFromWavenumber(init_wavenumber); 207 } 208 catch (Exception e) { 209 System.out.println("couldn't get chanIdx, using zero"); 210 } 211 subset.put(SpectrumAdapter.channelIndex_name, new double[] {chanIdx, chanIdx, 1}); 212 return subset; 213 } 214 215}