/* Copyright (c) 2011 Danish Maritime Authority
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
package dk.dma.ais.abnormal.util;
import com.google.common.collect.ImmutableMap;
import java.util.Map;
import java.util.TreeMap;
/**
* The Categorizer maps vessel properties into "categories"
* (or "buckets") for use by those Analyses which require
* categorized/bucketted statistic data.
*
* Numbering of categories starts from 0 (as this is consistent
* with indexing used by e.g. ThreeKeyMap and FourKeyMap.
*
*/
public final class Categorizer {
private final static String[] SHIP_TYPE_CATEGORIES = {
"tanker", // 1
"cargo", // 2
"passenger", // 3
"support", // 4
"fishing", // 5
"class b", // 6
"other", // 7
"undef" // 8
};
private final static String[] SHIP_SIZE_CATEGORIES = {
"undef", // 1
"1-50m", // 2
"50-100m", // 3
"100-200m", // 4
"200-999m" // 5
};
private final static String[] COG_CATEGORIES = {
"000-030", // 1
"030-060", // 2
"060-090", // 3
"090-120", // 4
"120-150", // 5
"150-180", // 6
"180-210", // 7
"210-240", // 8
"240-270", // 9
"270-300", // 10
"300-330", // 11
"330-360" // 12
};
private final static String[] SOG_CATEGORIES = {
"0-1kts", // 1
"1-5kts", // 2
"5-10kts", // 3
"10-15kts", // 4
"15-20kts", // 5
"20-30kts", // 6
"30-50kts", // 7
"50-100kts" // 8
};
public static final int NUM_SHIP_TYPE_CATEGORIES = SHIP_TYPE_CATEGORIES.length;
public static final int NUM_SHIP_SIZE_CATEGORIES = SHIP_SIZE_CATEGORIES.length;
public static final int NUM_COURSE_OVER_GROUND_CATEGORIES = COG_CATEGORIES.length;
public static final int NUM_SPEED_OVER_GROUND_CATEGORIES = SOG_CATEGORIES.length;
private static Map<Short, String> ALL_SHIP_TYPE_CATEGORY_MAPPINGS;
private static Map<Short, String> ALL_SHIP_SIZE_CATEGORY_MAPPINGS;
private static Map<Short, String> ALL_COURSE_OVER_GROUND_CATEGORY_MAPPINGS;
private static Map<Short, String> ALL_SPEED_OVER_GROUND_CATEGORY_MAPPINGS;
static {
ALL_SHIP_TYPE_CATEGORY_MAPPINGS = initMapping(ALL_SHIP_TYPE_CATEGORY_MAPPINGS, SHIP_TYPE_CATEGORIES);
ALL_SHIP_SIZE_CATEGORY_MAPPINGS = initMapping(ALL_SHIP_SIZE_CATEGORY_MAPPINGS, SHIP_SIZE_CATEGORIES);
ALL_COURSE_OVER_GROUND_CATEGORY_MAPPINGS = initMapping(ALL_COURSE_OVER_GROUND_CATEGORY_MAPPINGS, COG_CATEGORIES);
ALL_SPEED_OVER_GROUND_CATEGORY_MAPPINGS = initMapping(ALL_SPEED_OVER_GROUND_CATEGORY_MAPPINGS, SOG_CATEGORIES);
}
private static ImmutableMap<Short, String> initMapping(Map mapping, String[] categories) {
mapping = new TreeMap<>();
for (short c=1; c<=categories.length; c++) {
mapping.put(c, mapCategoryToString(categories, c));
}
return ImmutableMap.copyOf(mapping);
}
/**
* Map AIS ship type to DMA category
* @param shipType
* @return
*/
public static short mapShipTypeToCategory(int shipType) {
short category = 8;
if (shipType > 79 && shipType < 90) {
category = 1;
} else if (shipType > 69 && shipType < 80) {
category = 2;
} else if ((shipType > 39 && shipType < 50) || (shipType > 59 && shipType < 70)) {
category = 3;
} else if ((shipType > 30 && shipType < 36) || (shipType > 49 && shipType < 56)) {
category = 4;
} else if (shipType == 30) {
category = 5;
} else if (shipType == 36 || shipType == 37) { // TODO Class B
category = 6;
} else if ((shipType > 0 && shipType < 30) || (shipType > 89 && shipType < 100)) {
category = 7;
} else if (shipType == 0) {
category = 8;
}
return (short) category;
}
/**
* Map AIS ship length to DMA category
* @param shipLength
* @return
*/
public static short mapShipLengthToCategory(int shipLength) {
short category;
if (shipLength >= 0 && shipLength < 1) {
category = 1;
} else if (shipLength >= 1 && shipLength < 50) {
category = 2;
} else if (shipLength >= 50 && shipLength < 100) {
category = 3;
} else if (shipLength >= 100 && shipLength < 200) {
category = 4;
} else if (shipLength >= 200 && shipLength < 999) {
category = 5;
} else {
throw new IllegalArgumentException("shipLength: " + shipLength);
}
return (short) category;
}
/**
* Map course to DMA category
* @param cog
* @return
*/
public static short mapCourseOverGroundToCategory(float cog) {
cog = cog % (float) 360.0;
return (short) ((short) (cog / 30) + 1);
}
/**
* Map speed over ground to DMA category
* @param sog
* @return
*/
public static short mapSpeedOverGroundToCategory(float sog) {
short category;
if (sog >= 0 && sog < 1) {
category = 1;
} else if (sog >= 1 && sog < 5) {
category = 2;
} else if (sog >= 5 && sog < 10) {
category = 3;
} else if (sog >= 10 && sog < 15) {
category = 4;
} else if (sog >= 15 && sog < 20) {
category = 5;
} else if (sog >= 20 && sog < 30) {
category = 6;
} else if (sog >= 30 && sog < 50) {
category = 7;
} else {
category = 8;
}
return (short) category;
}
/**
* Map ship type category to English text
* @param category
* @return
*/
public static String mapShipTypeCategoryToString(short category) {
return mapCategoryToString(SHIP_TYPE_CATEGORIES, category);
}
/**
* Map ship length category to English text
* @param category
* @return
*/
public static String mapShipSizeCategoryToString(short category) {
return mapCategoryToString(SHIP_SIZE_CATEGORIES, category);
}
/**
* Map course over ground category to text
* @param category
* @return
*/
public static String mapCourseOverGroundCategoryToString(short category) {
return mapCategoryToString(COG_CATEGORIES, category);
}
/**
* Map speed over ground category to text
* @param category
* @return
*/
public static String mapSpeedOverGroundCategoryToString(short category) {
return mapCategoryToString(SOG_CATEGORIES, category);
}
private static String mapCategoryToString(String[] categories, short category) {
String categoryAsString;
if (category >= 1 && category <= categories.length) {
categoryAsString = categories[category-1];
} else {
categoryAsString = String.valueOf(category);
}
return categoryAsString;
}
public static Map<Short, String> getAllShipTypeCategoryMappings() {
return ALL_SHIP_TYPE_CATEGORY_MAPPINGS;
}
public static Map<Short, String> getAllShipSizeCategoryMappings() {
return ALL_SHIP_SIZE_CATEGORY_MAPPINGS;
}
public static Map<Short, String> getAllCourseOverGroundCategoryMappings() {
return ALL_COURSE_OVER_GROUND_CATEGORY_MAPPINGS;
}
public static Map<Short, String> getAllSpeedOverGroundCategoryMappings() {
return ALL_SPEED_OVER_GROUND_CATEGORY_MAPPINGS;
}
}