/* * Copyright (C) 2007 Steve Ratcliffe * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program 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 General Public License for more details. * * * Author: Steve Ratcliffe * Create date: Dec 6, 2007 */ package uk.me.parabola.mkgmap.filters; import java.awt.Rectangle; import java.awt.geom.Area; import java.util.List; import uk.me.parabola.imgfmt.app.Coord; import uk.me.parabola.mkgmap.general.MapShape; import uk.me.parabola.util.Java2DConverter; /** * @author Steve Ratcliffe */ public class PolygonSplitterBase extends BaseFilter { protected static final int MAX_SIZE = 0xffff; // larger value causes problem in delta encoding of lines private int shift; public void init(FilterConfig config) { shift = config.getShift(); } /** * Split the given shape and place the resulting shapes in the outputs list. * @param shape The original shape (that is too big). * @param outputs The output list. */ protected void split(MapShape shape, List<MapShape> outputs) { // TODO: use different algo which will keep track of holes which are // connected with the outer polygon // Convert to a awt area Area area = Java2DConverter.createArea(shape.getPoints()); // Get the bounds of this polygon Rectangle bounds = area.getBounds(); if (bounds.isEmpty()) return; // Drop it int half = 1 << (shift - 1); // 0.5 shifted int mask = ~((1 << shift) - 1); // to remove fraction bits // Cut the bounding box into two rectangles. The position of the common // line is rounded to the current resolution. Rectangle r1; Rectangle r2; if (bounds.width > bounds.height) { int halfWidth = bounds.width / 2; if (shift != 0){ halfWidth = (halfWidth + half) & mask; if (halfWidth == 0 || halfWidth == bounds.width) halfWidth = bounds.width / 2; } r1 = new Rectangle(bounds.x, bounds.y, halfWidth, bounds.height); r2 = new Rectangle(bounds.x + halfWidth, bounds.y, bounds.width - halfWidth, bounds.height); } else { int halfHeight = bounds.height / 2; if (shift != 0){ halfHeight = (halfHeight + half) & mask; if (halfHeight== 0 || halfHeight == bounds.height) halfHeight = bounds.height / 2; } r1 = new Rectangle(bounds.x, bounds.y, bounds.width, halfHeight); r2 = new Rectangle(bounds.x, bounds.y + halfHeight, bounds.width, bounds.height - halfHeight); } // Now find the intersection of these two boxes with the original // polygon. This will make two new areas, and each area will be one // (or more) polygons. Area clipper = new Area(r1); clipper.intersect(area); areaToShapes(shape, clipper, outputs); clipper = new Area(r2); clipper.intersect(area); areaToShapes(shape, clipper, outputs); } /** * Convert the area back into {@link MapShape}s. It is possible that the * area is multiple discontinuous polygons, so you may append more than one * shape to the output list. * * @param origShape The original shape, this is only used as a prototype to * copy for the newly created shapes. * @param area The area to be converted. * @param outputs Used to hold output shapes. */ private void areaToShapes(MapShape origShape, Area area, List<MapShape> outputs) { List<List<Coord>> subShapePoints = Java2DConverter.areaToShapes(area); for (List<Coord> subShape : subShapePoints) { MapShape s = origShape.copy(); s.setPoints(subShape); outputs.add(s); } } }