public Point2D getCenterPoint() { if (centerPoint == null) { centerPoint = new Point2D.Double( area.getBounds().x + area.getBounds().width / 2, area.getBounds().y + area.getBounds().height / 2); } return centerPoint; }
/** * Like copyFrom, but will only copy the area specified. * * @see TileLayer#copyFrom(MapLayer) * @param other * @param mask */ @Override public void maskedCopyFrom(MapLayer other, Area mask) { Rectangle boundBox = mask.getBounds(); for (int y = boundBox.y; y < boundBox.y + boundBox.height; y++) { for (int x = boundBox.x; x < boundBox.x + boundBox.width; x++) { if (mask.contains(x, y)) { setTileAt(x, y, ((TileLayer) other).getTileAt(x, y)); } } } }
// generate the capital by finding the center of the largest landmass. // this method can only be called after the AgriculturalUnit's regions have been set. private MapPoint calCapitolLocation() { if (entities == null) throw new RuntimeException("(!) regions not set!"); if (entities.isEmpty()) throw new RuntimeException("(!) no regions !"); int maxArea = 0; Area largest = null; for (AgriculturalUnit region : entities) { Area poly = region.getArea(); int area = (int) (poly.getBounds().getWidth() * poly.getBounds().getHeight()); if (area >= maxArea) { largest = poly; maxArea = area; } } int x = (int) largest.getBounds().getCenterX(); int y = (int) largest.getBounds().getCenterY(); return AgriculturalUnit.converter.pointToMapPoint(new Point(x, y)); }
public CanBeCutObject(Area area, double x, double y, double vx, double vy) { for (int i = 0; i < 3; i++) { this.x[i] = x; this.y[i] = y; this.vx[i] = vx; this.vy[i] = vy; } this.area = area; formerArea = computeArea(area.getBounds()); asMove1.translate(this.x[0], this.y[0]); this.area = new Area(asMove1.createTransformedShape(area)); }
/** * Like mergeOnto, but will only copy the area specified. * * @see TileLayer#mergeOnto(MapLayer) * @param other * @param mask */ @Override public void maskedMergeOnto(MapLayer other, Area mask) { Rectangle boundBox = mask.getBounds(); for (int y = boundBox.y; y < boundBox.y + boundBox.height; y++) { for (int x = boundBox.x; x < boundBox.x + boundBox.width; x++) { Tile tile = ((TileLayer) other).getTileAt(x, y); if (mask.contains(x, y) && tile != null) { setTileAt(x, y, tile); } } } }
// generate the capital by finding the center of the largest landmass. // this method can only be called after the Territory's regions have been set. private MapPoint calCapitolLocation() { if (regions == null) throw new RuntimeException("(!) regions not set!"); if (regions.isEmpty()) throw new RuntimeException("(!) no regions !"); int maxArea = 0; Area largest = null; for (GeographicArea region : regions) { Area poly = new Area(GeographicArea.mapConverter.regionToPolygon(region)); int area = (int) (poly.getBounds().getWidth() * poly.getBounds().getHeight()); if (area >= maxArea) { largest = poly; maxArea = area; } } if (largest == null) throw new IllegalStateException("Internal error computing largest region"); int x = (int) largest.getBounds().getCenterX(); int y = (int) largest.getBounds().getCenterY(); return Territory.converter.pointToMapPoint(new Point(x, y)); }
/** * Area "a" contains the hull that we would like to download data for. however we can only * download rectangles, so the following is an attempt at finding a number of rectangles to * download. * * <p>The idea is simply: Start out with the full bounding box. If it is too large, then split it * in half and repeat recursively for each half until you arrive at something small enough to * download. The algorithm is improved by always using the intersection between the rectangle and * the actual desired area. For example, if you have a track that goes like this: +----+ | /| | / * | | / | |/ | +----+ then we would first look at downloading the whole rectangle (assume it's * too big), after that we split it in half (upper and lower half), but we donot request the full * upper and lower rectangle, only the part of the upper/lower rectangle that actually has * something in it. * * <p>This functions calculates the rectangles, asks the user to continue and downloads the areas * if applicable. */ protected static void confirmAndDownloadAreas( Area a, double max_area, boolean osmDownload, boolean gpxDownload, String title, ProgressMonitor progressMonitor) { List<Rectangle2D> toDownload = new ArrayList<Rectangle2D>(); addToDownload(a, a.getBounds(), toDownload, max_area); if (toDownload.isEmpty()) { return; } JPanel msg = new JPanel(new GridBagLayout()); msg.add( new JLabel( tr( "<html>This action will require {0} individual<br>" + "download requests. Do you wish<br>to continue?</html>", toDownload.size())), GBC.eol()); if (JOptionPane.OK_OPTION != JOptionPane.showConfirmDialog( Main.parent, msg, title, JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE)) { return; } final PleaseWaitProgressMonitor monitor = new PleaseWaitProgressMonitor(tr("Download data")); final Future<?> future = new DownloadTaskList().download(false, toDownload, osmDownload, gpxDownload, monitor); Main.worker.submit( new Runnable() { @Override public void run() { try { future.get(); } catch (Exception e) { e.printStackTrace(); return; } monitor.close(); } }); }
/** * Tests if two polygons intersect. * * @param first * @param second * @return intersection kind */ public static PolygonIntersection polygonIntersection(List<Node> first, List<Node> second) { Area a1 = getArea(first); Area a2 = getArea(second); Area inter = new Area(a1); inter.intersect(a2); Rectangle bounds = inter.getBounds(); if (inter.isEmpty() || bounds.getHeight() * bounds.getWidth() <= 1.0) { return PolygonIntersection.OUTSIDE; } else if (inter.equals(a1)) { return PolygonIntersection.FIRST_INSIDE_SECOND; } else if (inter.equals(a2)) { return PolygonIntersection.SECOND_INSIDE_FIRST; } else { return PolygonIntersection.CROSSING; } }
/** * Creates a master shape of the letter. * * @param shape * @return the master shape */ private final Master createMaster(RenderContext ctx, Shape shape, double ascent) { final Area area = new Area(shape); final double scale = MASTER_HEIGHT / ascent; area.transform(AffineTransform.getScaleInstance(scale, scale)); final Rectangle bounds = area.getBounds(); // System.out.println("createMaster bounds " + bounds); // area.transform(AffineTransform.getTranslateInstance(-bounds.getMinX(), // -bounds.getMinY())); // bounds = area.getBounds(); final int minX = (int) (bounds.getMinX() - 0.5); final int maxX = (int) (bounds.getMaxX() + 0.5); final int minY = (int) (bounds.getMinY() - 0.5); final int maxY = (int) (bounds.getMaxY() + 0.5); final int width = maxX - minX; final int height = maxY - minY; BitSet bits = (BitSet) ctx.getObject(BITS_NAME); if (bits == null) { bits = new BitSet(width * height); ctx.setObject(BITS_NAME, bits); } else { bits.clear(); } int ofs = 0; for (int y = maxY; y > minY; y--) { for (int x = minX; x < maxX; x++) { if (area.contains(x, y)) { bits.set(ofs); } ofs++; } } return new Master(bits, width, height, minX, minY); }
@Override public void draw( Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, IDrawingObserver drawingObserver) { if (checkPointsClipped(g2d.getClip())) { return; } int pinSize = (int) PIN_SIZE.convertToPixels() / 2 * 2; Area mainArea = getBody(); Composite oldComposite = g2d.getComposite(); if (alpha < MAX_ALPHA) { g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); } g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor); g2d.fill(mainArea); g2d.setComposite(oldComposite); Color finalBorderColor; Theme theme = (Theme) ConfigurationManager.getInstance() .readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); if (outlineMode) { finalBorderColor = componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : theme.getOutlineColor(); } else { finalBorderColor = componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR : borderColor; } g2d.setColor(finalBorderColor); g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); g2d.draw(mainArea); for (Point point : controlPoints) { if (!outlineMode) { g2d.setColor(PIN_COLOR); g2d.fillOval(point.x - pinSize / 2, point.y - pinSize / 2, pinSize, pinSize); } g2d.setColor(outlineMode ? theme.getOutlineColor() : PIN_BORDER_COLOR); g2d.drawOval(point.x - pinSize / 2, point.y - pinSize / 2, pinSize, pinSize); } // Draw label. g2d.setFont(LABEL_FONT); Color finalLabelColor; if (outlineMode) { finalLabelColor = componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED : theme.getOutlineColor(); } else { finalLabelColor = componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED : getLabelColor(); } g2d.setColor(finalLabelColor); String label = (getDisplay() == Display.NAME) ? getName() : getValue(); FontMetrics fontMetrics = g2d.getFontMetrics(g2d.getFont()); Rectangle2D rect = fontMetrics.getStringBounds(label, g2d); int textHeight = (int) (rect.getHeight()); int textWidth = (int) (rect.getWidth()); // Center text horizontally and vertically Rectangle bounds = mainArea.getBounds(); int x = bounds.x + (bounds.width - textWidth) / 2; int y = bounds.y + (bounds.height - textHeight) / 2 + fontMetrics.getAscent(); g2d.drawString(label, x, y); }
protected void cutTheArea(ArrayList<Point2D> sawtooth) { // TODO Auto-generated method stub int x = (int) pointList.get(0).getX() - (int) pointList.get(pointList.size() - 1).getX(); int y = (int) pointList.get(0).getY() - (int) pointList.get(pointList.size() - 1).getY(); int formerX = (int) pointList.get(pointList.size() - 1).getX(); int formerY = (int) pointList.get(pointList.size() - 1).getY(); // 切割添加的第一个点,为水滴离开时的点,延切割方向平移一大段距离 Point2D firstPoint = new Point(formerX - 10 * x, formerY - 10 * y); sawtooth.add(firstPoint); // 假如方向为从左上穿过到右下, 先右移一个很大的值,再上移一个很大的值 int xDirection = 1; int yDirection = 1; if (x < 0) { // 使其与x,y同号 xDirection = -1; } sawtooth.add(new Point((int) firstPoint.getX() - xDirection * 1000, (int) firstPoint.getY())); sawtooth.add( new Point( (int) firstPoint.getX() - xDirection * 1000, (int) firstPoint.getY() - yDirection * 5000)); sawtooth.add( new Point( (int) firstPoint.getX() + xDirection * 2000, (int) firstPoint.getY() - yDirection * 5000)); formerX = (int) pointList.get(0).getX(); formerY = (int) pointList.get(0).getY(); // 切割添加的最后一个点,为水滴离开时的点,延切割反方向平移一大段距离 Point2D lastPoint = new Point(formerX + 10 * x, formerY + 10 * y); sawtooth.add(lastPoint); xList = new int[sawtooth.size()]; yList = new int[sawtooth.size()]; // 为了多边形的声明,将x,y坐标都变成一个int[] for (int i = 0; i < sawtooth.size(); i++) { xList[i] = (int) sawtooth.get(i).getX(); yList[i] = (int) sawtooth.get(i).getY(); } // 开始切割 Polygon cutPolygon = new Polygon(xList, yList, sawtooth.size()); Area cutArea = new Area(cutPolygon); cutArea.intersect(area); // 这里cutArea是切下来的部分,永远靠上 area.subtract(cutArea); // 这里area是剩下的部分,靠下 // 如果被切下来部分的面积大于原面积的0.75,那么把cutArea1变为另一部分 // ,把原area变为该area,假如两个都不大于原来面积的0.75,那么都变为cutArea(即将消失的部分) // 顺便把每一部分的速度改一下,速度是将水滴的速度方向向上旋转30°,和向下旋转30°,生成两个新的速度向量,叠加到原来的速度上。 // 生成两个新向量,式子是通过方程推导出来的,index 0为靠下部分速度,1为靠上部分速度 double[] deltavx = { Math.sqrt(3) * waterDrop_vx * 0.5 - 0.5 * (Math.abs(waterDrop_vx) / waterDrop_vx) * waterDrop_vy, Math.sqrt(3) * waterDrop_vx * 0.5 + 0.5 * (Math.abs(waterDrop_vx) / waterDrop_vx) * waterDrop_vy }; double[] deltavy = { Math.sqrt(3) * waterDrop_vy * 0.5 + 0.5 * (Math.abs(waterDrop_vx)), Math.sqrt(3) * waterDrop_vy * 0.5 - 0.5 * (Math.abs(waterDrop_vx)) }; if ((computeArea(area.getBounds()) < formerArea * 0.3) && (computeArea(cutArea.getBounds())) > formerArea * 0.8) { cutArea1 = area; area = cutArea; vx[0] = vx[0] + deltavx[1]; vy[0] = vy[0] + deltavy[1]; vx[1] = vx[1] + deltavx[0]; vy[1] = vy[1] + deltavy[0]; } else if ((computeArea(cutArea.getBounds()) < formerArea * 0.3) && (computeArea(area.getBounds())) > formerArea * 0.8) { cutArea1 = cutArea; vx[1] = vx[1] + deltavx[1]; vy[1] = vy[1] + deltavy[1]; vx[0] = vx[0] + deltavx[0]; vy[0] = vy[0] + deltavy[0]; } else { cutArea1 = cutArea; cutArea2 = area; area = new Area(); vx[1] = vx[1] + deltavx[1]; vy[1] = vy[1] + deltavy[1]; vx[2] = vx[2] + deltavx[0]; vy[2] = vy[2] + deltavy[0]; } pointList = new ArrayList<Point2D>(); this.sawtooth = new ArrayList<Point2D>(); isPassed = false; sawtoothIndex = 0; }
static void renderTextWithJavaFonts( GraphicsState gs, DynamicVectorRenderer current, int streamType, ParserOptions parserOptions, PdfFont currentFontData, GlyphData glyphData, final int Tmode, final float currentWidth, final boolean isTextShifted, final PdfJavaGlyphs glyphs, final float[][] Trm) { final float actualWidth = glyphData.getActualWidth(); /** set values used if rendering as well */ Object transformedGlyph2; AffineTransform glyphAt = null; final int rawInt = glyphData.getRawInt(); // { // render now final boolean isSTD = actualWidth > 0 || DecoderOptions.isRunningOnMac || streamType == ValueTypes.FORM || StandardFonts.isStandardFont(currentFontData.getBaseFontName(), false) || currentFontData.isBrokenFont(); /** flush cache if needed */ // if(!DynamicVectorRenderer.newCode2){ if (glyphs.lastTrm[0][0] != Trm[0][0] || glyphs.lastTrm[1][0] != Trm[1][0] || glyphs.lastTrm[0][1] != Trm[0][1] || glyphs.lastTrm[1][1] != Trm[1][1]) { glyphs.lastTrm = Trm; glyphs.flush(); } // } // either calculate the glyph to draw or reuse if already drawn Area glyph = glyphs.getCachedShape(rawInt); glyphAt = glyphs.getCachedTransform(rawInt); if (glyph == null) { double dY = -1, dX = 1, x3 = 0, y3 = 0; // allow for text running up the page if ((Trm[1][0] < 0 && Trm[0][1] >= 0) || (Trm[0][1] < 0 && Trm[1][0] >= 0)) { dX = 1f; dY = -1f; } if (isSTD) { glyph = glyphs.getGlyph(rawInt, glyphData.getDisplayValue(), currentWidth); // hack to fix problem with Java Arial font if (glyph != null && rawInt == 146 && glyphs.isArialInstalledLocally) { y3 = -(glyph.getBounds().height - glyph.getBounds().y); } } else { // remap font if needed String xx = glyphData.getDisplayValue(); GlyphVector gv1 = null; // do not show CID fonts as Lucida unless match if (!glyphs.isCIDFont || glyphs.isCorrupted() || glyphs.isFontInstalled) { gv1 = glyphs.getUnscaledFont().createGlyphVector(PdfJavaGlyphs.frc, xx); } if (gv1 != null) { glyph = new Area(gv1.getOutline()); // put glyph into display position double glyphX = gv1.getOutline().getBounds2D().getX(); // ensure inside box x3 = 0; if (glyphX < 0) { glyphX = -glyphX; x3 = glyphX * 2; // System.out.println(x3+" "+displayTrm[0][0]+" "+displayTrm[0][0]); if (Trm[0][0] > Trm[0][1]) { x3 *= Trm[0][0]; } else { x3 *= Trm[0][1]; } // glyphAt =AffineTransform.getTranslateInstance(x3,0); } final double glyphWidth = gv1.getVisualBounds().getWidth() + (glyphX * 2); final double scaleFactor = currentWidth / glyphWidth; if (scaleFactor < 1) { dX *= scaleFactor; } if (x3 > 0) { x3 *= dX; } } } glyphAt = new AffineTransform( dX * Trm[0][0], dX * Trm[0][1], dY * Trm[1][0], dY * Trm[1][1], x3, y3); // create shape for text using transformation to make correct size // glyphAt =new AffineTransform(dX* displayTrm[0][0],dX* displayTrm[0][1],dY* // displayTrm[1][0],dY* displayTrm[1][1] ,x3, y3); // save so we can reuse if it occurs again in this TJ command glyphs.setCachedShape(rawInt, glyph, glyphAt); } if (glyph != null && Tmode == GraphicsState.CLIPTEXT && glyph.getBounds().width > 0) { /** support for TR7 */ final Area glyphShape = (Area) glyph.clone(); // we need to apply to make it all work glyphShape.transform(glyphAt); // if its already generated we just need to move it if (parserOptions.renderDirectly()) { final AffineTransform at2 = AffineTransform.getTranslateInstance(Trm[2][0], (Trm[2][1])); glyphShape.transform(at2); } gs.addClip(glyphShape); // current.drawClip(gs,null,false); // if(parserOptions.renderDirectly()) { glyph = null; // } } transformedGlyph2 = glyph; } if (transformedGlyph2 != null) { final double[] textTrans = new double[6]; glyphAt.getMatrix(textTrans); final int fontSize = glyphData.getFontSize(); if (parserOptions.useJavaFX()) { current.drawEmbeddedText( Trm, fontSize, null, null, DynamicVectorRenderer.TEXT, gs, textTrans, glyphData.getUnicodeValue(), currentFontData, -100); } else // add to renderer if (parserOptions.renderDirectly()) { current.drawEmbeddedText( Trm, fontSize, null, transformedGlyph2, DynamicVectorRenderer.TEXT, gs, textTrans, glyphData.getUnicodeValue(), currentFontData, -100); } else { if (isTextShifted) { current.drawEmbeddedText( Trm, -fontSize, null, transformedGlyph2, DynamicVectorRenderer.TEXT, gs, null, glyphData.getUnicodeValue(), currentFontData, -100); } else { current.drawEmbeddedText( Trm, fontSize, null, transformedGlyph2, DynamicVectorRenderer.TEXT, gs, null, glyphData.getUnicodeValue(), currentFontData, -100); } } } }
/** * Creates a continuous legend item for one item in dimensionSet, i.e. dimensionSet must be a set * containing exactly one value. * * @param dateFormat format used to format minValue and maxValue as dates, or null if they should * be displayed numerically instead of as dates * @throws ChartPlottimeException */ private LegendItem createContinuousLegendItem( PlotInstance plotInstance, Set<PlotDimension> dimensionSet, double minValue, double maxValue, DateFormat dateFormat) { PlotConfiguration plotConfiguration = plotInstance.getCurrentPlotConfigurationClone(); PlotDimension dimension = dimensionSet.iterator().next(); DefaultDimensionConfig dimensionConfig = (DefaultDimensionConfig) plotConfiguration.getDimensionConfig(dimension); DimensionConfigData dimensionConfigData = plotInstance.getPlotData().getDimensionConfigData(dimensionConfig); // String label = dimensionConfig.getLabel(); // if(label == null) { // label = I18N.getGUILabel("plotter.unnamed_value_label"); // } String label = ""; if (dimension == PlotDimension.COLOR) { ColorProvider colorProvider = dimensionConfigData.getColorProvider(); if (!colorProvider.supportsNumericalValues()) { throw new RuntimeException( "Color provider for continuous legend item does not support numerical values."); } // shape dimensions final int width = 50; final int height = 10; // create item paint // first disable logarithmic scale on color provider ( -> linear gradient in legend) // ContinuousColorProvider continuousColorProvider = null; // if (dimensionConfig.isLogarithmic() && colorProvider instanceof // ContinuousColorProvider) { // continuousColorProvider = (ContinuousColorProvider)colorProvider; // continuousColorProvider.setLogarithmic(false); // } // calculate gradient float fractions[] = new float[width]; Color colors[] = new Color[width]; for (int i = 0; i < width; ++i) { float fraction = i / (width - 1.0f); double fractionValue; if (colorProvider instanceof ContinuousColorProvider && ((ContinuousColorProvider) colorProvider) .isColorMinMaxValueDifferentFromOriginal( ((ContinuousColorProvider) colorProvider).getMinValue(), ((ContinuousColorProvider) colorProvider).getMaxValue())) { fractionValue = ((ContinuousColorProvider) colorProvider).getMinValue() + fraction * (((ContinuousColorProvider) colorProvider).getMaxValue() - ((ContinuousColorProvider) colorProvider).getMinValue()); } else { fractionValue = minValue + fraction * (maxValue - minValue); } colors[i] = colorProvider.getColorForValue(fractionValue); fractions[i] = fraction; } LinearGradientPaint shapeFillPaint = new LinearGradientPaint( new Point(0, 0), new Point(width, 0), fractions, colors, CycleMethod.REPEAT); // reset color provider to logarithmic if necessary // if (continuousColorProvider != null && dimensionConfig.isLogarithmic()) { // continuousColorProvider.setLogarithmic(true); // } // create item shape Rectangle itemShape = new Rectangle(width, height); if (colorProvider instanceof ContinuousColorProvider) { return createFlankedShapeLegendItem( label, ((ContinuousColorProvider) colorProvider).getMinValue(), ((ContinuousColorProvider) colorProvider).getMaxValue(), itemShape, shapeFillPaint, true, dateFormat); } else { return createFlankedShapeLegendItem( label, minValue, maxValue, itemShape, shapeFillPaint, true, dateFormat); } } else if (dimension == PlotDimension.SHAPE) { // shape provider probably never supports numerical values return null; } else if (dimension == PlotDimension.SIZE) { SizeProvider sizeProvider = dimensionConfigData.getSizeProvider(); if (!sizeProvider.supportsNumericalValues()) { throw new RuntimeException( "Size provider for continuous legend item does not support numerical values."); } double minScalingFactor = sizeProvider.getMinScalingFactor(); double maxScalingFactor = sizeProvider.getMaxScalingFactor(); ContinuousSizeProvider legendSizeProvider = new ContinuousSizeProvider( minScalingFactor, maxScalingFactor, MIN_LEGEND_ITEM_SCALING_FACTOR, MAX_LEGEND_ITEM_SCALING_FACTOR, false); int legendItemCount = 4; Area composedShape = new Area(); Shape originalShape = UNDEFINED_SHAPE; if (dimensionSet.contains(PlotDimension.SIZE) && dimensionSet.size() == 1) { originalShape = UNDEFINED_SHAPE_AND_COLOR; } double maxHeight = originalShape.getBounds().getHeight() * MAX_LEGEND_ITEM_SCALING_FACTOR; for (int i = 0; i < legendItemCount; ++i) { double fraction = minScalingFactor + ((double) i / legendItemCount * (maxScalingFactor - minScalingFactor)); double legendScalingFactor = legendSizeProvider.getScalingFactorForValue(fraction); double composedWidth = composedShape.getBounds().getWidth(); AffineTransform t = new AffineTransform(); t.scale(legendScalingFactor, legendScalingFactor); Shape shape = t.createTransformedShape(originalShape); t = new AffineTransform(); double shapeWidth = shape.getBounds().getWidth(); double shapeHeight = shape.getBounds().getHeight(); t.translate(composedWidth + shapeWidth * .1, (maxHeight - shapeHeight) / 2.0); t.translate(-shape.getBounds().getMinX(), -shape.getBounds().getMinY()); shape = t.createTransformedShape(shape); composedShape.add(new Area(shape)); } return createFlankedShapeLegendItem( label, minValue, maxValue, composedShape, UNDEFINED_COLOR_PAINT, false, dateFormat); } else { throw new RuntimeException( "Unsupported dimension. Execution path should never reach this line."); } }