package com.baselet.control; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.baselet.control.basics.geom.Rectangle; import com.baselet.control.constants.SharedConstants; public class SharedUtils { private static final Logger log = LoggerFactory.getLogger(SharedUtils.class); public static int realignToGrid(double d) { return realignTo(true, d, false, SharedConstants.DEFAULT_GRID_SIZE); } /** * realigns a rectangle to the grid enlarging any side if necessary (eg: x=9, width=10, x2=19 will be realigned to x=0, width=20, x2=20) * * @param rectangle rectangle to realign * @return a realigned copy of the input rectangle * @param realignHeightAndWidth if true height and width are also realigned if necessary */ public static Rectangle realignToGrid(Rectangle rectangle, boolean realignHeightAndWidth) { int x = realignToGrid(false, rectangle.getX(), false); int y = realignToGrid(false, rectangle.getY(), false); if (realignHeightAndWidth) { int width = realignToGrid(false, rectangle.getX() - x + rectangle.getWidth(), true); // IMPORTANT: the difference from original x and realigned x must be added, otherwise the upper example would return x=0, width=10, x2=10. x2 would be too small int height = realignToGrid(false, rectangle.getY() - y + rectangle.getHeight(), true); return new Rectangle(x, y, width, height); } else { return new Rectangle(x, y, rectangle.getWidth(), rectangle.getHeight()); } } /** * rounds eg: 5 to 10, 4 to 0, -5 to -10, -4 to 0 */ public static int realignToGridRoundToNearest(boolean logRealign, double val) { boolean roundUp; if (Math.abs(val % SharedConstants.DEFAULT_GRID_SIZE) < SharedConstants.DEFAULT_GRID_SIZE / 2) { roundUp = val < 0; } else { roundUp = val >= 0; } return realignTo(logRealign, val, roundUp, SharedConstants.DEFAULT_GRID_SIZE); } public static int realignToGrid(boolean logRealign, double val, boolean roundUp) { return realignTo(logRealign, val, roundUp, SharedConstants.DEFAULT_GRID_SIZE); } /** * returns the integer which is nearest to val but on the grid (round down) * * @param logRealign * if true a realign is logged as an error * @param val * value which should be rounded to the grid * @param roundUp * if true the realign rounds up instead of down * @return value on the grid */ public static int realignTo(boolean logRealign, double val, boolean roundUp, int gridSize) { double alignedVal = val; double mod = val % gridSize; if (mod != 0) { alignedVal -= mod; // ExampleA: 14 - 4 = 10 // ExampleB: -14 - -4 = -10 // (positive vals get round down, negative vals get round up) if (val > 0 && roundUp) { // eg ExampleA: 10 + 10 = 20 (for positive vals roundUp must be specifically handled by adding gridSize) alignedVal += gridSize; } if (val < 0 && !roundUp) { // eg ExampleB: -10 - 10 = -20 (for negative vals roundDown must be specifically handled by subtracting gridSize) alignedVal -= gridSize; } if (logRealign) { log.error("realignToGrid from " + val + " to " + alignedVal); } } return (int) alignedVal; } public static String listToString(String sep, Collection<?> list) { return listToStringHelper(new StringBuilder(), sep, list).toString(); } private static StringBuilder listToStringHelper(StringBuilder sb, String sep, Collection<?> list) { for (Object line : list) { sb.append(line).append(sep); } if (sb.length() > 0) { sb.setLength(sb.length() - sep.length()); } return sb; } public static String mapToString(Map<?, ?> map) { return mapToString("\n", ",", map); } public static String mapToString(String mapSep, String listSep, Map<?, ?> map) { StringBuilder sb = new StringBuilder(); for (Entry<?, ?> e : map.entrySet()) { sb.append(e.getKey()).append(": "); if (e.getValue() instanceof Collection<?>) { listToStringHelper(sb, listSep, (Collection<?>) e.getValue()); } else { sb.append(e.getValue().toString()); } sb.append(mapSep); } if (sb.length() > 0) { sb.setLength(sb.length() - mapSep.length()); } return sb.toString(); } public static <T> List<T> mergeLists(List<T> listA, List<T> listB, List<T> listC) { List<T> returnList = new ArrayList<T>(listA); returnList.addAll(listB); returnList.addAll(listC); return Collections.unmodifiableList(returnList); } public static Double[][] cloneArray(Double[][] src) { int length = src.length; Double[][] target = new Double[length][src[0].length]; for (int i = 0; i < length; i++) { System.arraycopy(src[i], 0, target[i], 0, src[i].length); } return target; } public static String[] cloneArray(String[] src) { String[] target = new String[src.length]; System.arraycopy(src, 0, target, 0, src.length); return target; } public static int[] cloneArray(int[] src) { int[] target = new int[src.length]; System.arraycopy(src, 0, target, 0, src.length); return target; } /** * if the user types "\n" it should be translated to a linebreak. He can avoid this by typing \\n (escaping the linebreak) */ public static String[] splitAtLineEndChar(String text) { String rep = StringStyle.replaceNotEscaped(text, "\\n", "\n"); if (rep.contains("\n")) { String[] split = rep.split("\n"); // split uses a RegEx therefore escape the linebreak char return split; } return new String[] { text }; } }