001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2024
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.ui;
030
031import java.awt.Color;
032
033import java.io.BufferedReader;
034import java.io.InputStream;
035import java.io.InputStreamReader;
036
037import java.util.ArrayList;
038import java.util.List;
039import java.util.StringTokenizer;
040
041import org.w3c.dom.Element;
042
043import ucar.unidata.util.ColorTable;
044import ucar.unidata.util.IOUtil;
045import ucar.unidata.util.StringUtil;
046
047import edu.wisc.ssec.mcidasv.util.XPathUtils;
048
049/**
050 * A class to provide color tables suitable for data displays.
051 * Uses some code by Ugo Taddei. All methods are static.
052 */
053public class McIdasColorTableDefaults {
054
055    /** The name of the "aod" color table */
056    public static final String NAME_AOD = "AOD";
057
058    /** The name of the "cot" color table */
059    public static final String NAME_COT = "COT";
060
061    /**
062     * Create a ColorTable and add it to the given list
063     *
064     * @param name The CT name
065     * @param category Its category
066     * @param table The actual data
067     * @return The color table
068     */
069    public static ColorTable createColorTable(String name, String category,
070            float[][] table) {
071        return createColorTable(new ArrayList(), name, category, table);
072    }
073
074
075    /**
076     * _more_
077     *
078     * @param l _more_
079     * @param name _more_
080     * @param category _more_
081     * @param table _more_
082     *
083     * @return _more_
084     */
085    public static ColorTable createColorTable(ArrayList l, String name,
086            String category, float[][] table) {
087        return createColorTable(l, name, category, table, false);
088    }
089
090    /**
091     * Create a ColorTable and add it to the given list
092     *
093     * @param l List to add the ColorTable to
094     * @param name The CT name
095     * @param category Its category
096     * @param table The actual data
097     * @param tableFlipped If true then the table data is not in row major order
098     * @return The color table
099     */
100    public static ColorTable createColorTable(ArrayList l, String name,
101            String category, float[][] table, boolean tableFlipped) {
102
103        // ensure all R G and B values in the table are in 0.0 to 1.0 range
104        for (int i = 0; i < table.length; i++) {
105            for (int j = 0; j < table[i].length; j++) {
106                if (table[i][j] < 0.0) {
107                    //System.out.println(" bad value "+table [i][j] );
108                    table[i][j] = 0.0f;
109                } else if (table[i][j] > 1.0) {
110                    //System.out.println(" bad value "+table [i][j]+" for table "
111                    // +name +"  comp "+i+"  pt "+j);
112                    table[i][j] = 1.0f;
113                }
114            }
115        }
116
117        ColorTable colorTable = new ColorTable(name.toUpperCase(), name,
118                                    category, table, tableFlipped);
119        l.add(colorTable);
120        return colorTable;
121    }
122
123    /**
124     * Read in and process a hydra color table
125     *
126     * @param name File name
127     * @return The processed CT data
128     *
129     * @throws IllegalArgumentException
130     */
131    public static final float[][] makeTableFromASCII(String name)
132            throws IllegalArgumentException {
133        float colorTable[][];
134        try {
135            InputStream is = IOUtil.getInputStream(name);
136            BufferedReader reader = new BufferedReader(
137                new InputStreamReader(is));
138            String lineOut = reader.readLine();
139            StringTokenizer tok = null;
140            List reds = new ArrayList();
141            List greens = new ArrayList();
142            List blues = new ArrayList();
143            while (lineOut != null) {
144                if (!lineOut.startsWith("!")) {
145                    tok = new StringTokenizer(lineOut," ");
146                    reds.add(tok.nextToken());
147                    greens.add(tok.nextToken());
148                    blues.add(tok.nextToken());
149                }
150                lineOut = reader.readLine();
151            }
152            if (StringUtil.isDigits((String)reds.get(0))) {
153                colorTable = processInts(reds, greens, blues);
154            } else {
155                colorTable = processFloats(reds, greens, blues);
156            }
157        } catch (Exception e) {
158            throw new IllegalArgumentException(e.toString());
159        }
160        return colorTable;
161    }
162
163    /**
164     * Convert a AWIPS II {@literal ".cmap"} file to an IDV {@link ColorTable}
165     * and add the new color table to the {@link McIdasColorTableManager}.
166     * 
167     * @param name Name to use in the color table manager.
168     * @param category Category of the color table.
169     * @param file Path to AWIPS II {@literal ".cmap"} file.
170     * 
171     * @return Either a {@link List} containing the newly created 
172     *         {@code ColorTable} or {@code null} if the conversion failed.
173     */
174    public static List makeAwips2ColorTables(String name, String category, 
175                                             String file) 
176    {
177        String xpath = "//color";
178        // yes, I should be using "List<Color> ....", but some IDV methods
179        // expect ArrayList (for no good reason)
180        ArrayList<Color> colors = new ArrayList<>(512);
181        for (Element e : XPathUtils.elements(file, xpath)) {
182            float r = Float.valueOf(e.getAttribute("r"));
183            float g = Float.valueOf(e.getAttribute("g"));
184            float b = Float.valueOf(e.getAttribute("b"));
185            float a = Float.valueOf(e.getAttribute("a"));
186
187            // some files will have alpha values of "3.0"; we just clamp these
188            // to 1.0.
189            if (a > 1.0) {
190                a = 1.0f;
191            }
192            
193            colors.add(new Color(r, g, b, a));
194        }
195
196        List<ColorTable> newColorTable = null;
197        if (!colors.isEmpty()) {
198            newColorTable = new ArrayList<>(1);
199            newColorTable.add(makeColorTable(name, category, colors));
200        }
201        return newColorTable;
202    }
203
204    /**
205     * Convert strings of integers to scaled colors.
206     *
207     * @param reds Array containing red strings.
208     * @param greens Array containing green strings.
209     * @param blues Array containing blue strings.
210     *
211     * @return Color table of scaled floats.
212     */
213    static private float[][] processInts(List reds, List greens, List blues) {
214        List colors = new ArrayList();
215        int red = 0;
216        int green = 0;
217        int blue = 0;
218        int num = reds.size();
219        float colorTable[][] = new float[3][num];
220        for (int i=0; i<num; i++) {
221            red = new Integer((String)reds.get(i)).intValue();
222            green = new Integer((String)greens.get(i)).intValue();
223            blue = new Integer((String)blues.get(i)).intValue();
224            colors.add(new Color(red, green, blue));
225        }
226        colorTable = toArray(colors);
227        return colorTable;
228    }
229
230
231    /**
232     * Convert strings of floats to scaled colors.
233     *
234     * @param reds List containing red strings.
235     * @param greens List containing green strings.
236     * @param blues List containing blue strings.
237     *
238     * @return Color table of scaled floats.
239     */
240    static private float[][] processFloats(List reds, List greens, List blues) {
241        int num = reds.size();
242        float colorTable[][] = new float[3][num];
243        for (int i=0; i<num; i++) {
244            colorTable[0][i] = new Float((String)reds.get(i)).floatValue();
245            colorTable[1][i] = new Float((String)greens.get(i)).floatValue();
246            colorTable[2][i] = new Float((String)blues.get(i)).floatValue();
247        }
248        return colorTable;
249    }
250
251    /**
252     * Utility to convert list of colors to float array
253     *
254     * @param colors colors
255     *
256     * @return color array
257     */
258    private static float[][] toArray(List colors) {
259        float colorTable[][] = new float[3][colors.size()];
260        for (int i = 0; i < colors.size(); i++) {
261            Color c = (Color) colors.get(i);
262            colorTable[0][i] = ((float) c.getRed()) / 255.f;
263            colorTable[1][i] = ((float) c.getGreen()) / 255.f;
264            colorTable[2][i] = ((float) c.getBlue()) / 255.f;
265/*
266            System.out.println(colorTable[0][i] + " " +
267                               colorTable[1][i] + " " +
268                               colorTable[2][i]);
269*/
270        }
271        return colorTable;
272    }
273
274
275    /**
276     * _more_
277     *
278     * @param name _more_
279     * @param cat _more_
280     * @param colors _more_
281     *
282     * @return _more_
283     */
284    private static ColorTable makeColorTable(String name, String cat,
285                                             ArrayList colors) {
286        ColorTable ct = new ColorTable(name, cat, null);
287        ct.setTable(colors);
288        return ct;
289    }
290}