/* * Copyright 2010, 2011, 2012 mapsforge.org * Copyright 2013 Hannes Janetzek * * This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * * This program 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 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with * this program. If not, see <http://www.gnu.org/licenses/>. */ package org.oscim.layers.tile.vector.labeling; import org.oscim.core.Tile; import org.oscim.renderer.bucket.TextItem; import org.oscim.theme.styles.TextStyle; import org.oscim.utils.geom.GeometryUtils; import org.oscim.utils.geom.LineClipper; public final class WayDecorator { public static void renderText(LineClipper clipper, float[] coordinates, String string, TextStyle text, int pos, int len, LabelTileData ld) { //TextItem items = textItems; TextItem t = null; // calculate the way name length plus some margin of safety float labelWidth = -1; float minWidth = Tile.SIZE / 10; //final int min = 0; //final int max = Tile.SIZE; // find way segments long enough to draw the way name on them for (int i = pos; i < pos + len - 2; i += 2) { // get the first way point coordinates float prevX = coordinates[i + 0]; float prevY = coordinates[i + 1]; byte edge = 0; //clipper.clipStart(prevX, prevY); // get the current way point coordinates float curX = coordinates[i + 2]; float curY = coordinates[i + 3]; //int clip; //if ((clip = clipper.clipNext(curX, curY)) != 0) { // if (clip < 0) { // prevX = clipper.out[0]; // prevY = clipper.out[1]; // curX = clipper.out[2]; // curY = clipper.out[3]; // // if (prevX == min) // edge |= 1 << 0; // else if (prevX == max) // edge |= 1 << 1; // // if (prevY == min) // edge |= 1 << 2; // else if (prevY == max) // edge |= 1 << 3; // // if (curX == min) // edge |= 1 << 4; // else if (curX == max) // edge |= 1 << 5; // // if (curY == min) // edge |= 1 << 5; // else if (curY == max) // edge |= 1 << 6; // } //} int last = i; // calculate the length of the current segment (Euclidian distance) float vx = prevX - curX; float vy = prevY - curY; if (vx == 0 && vy == 0) continue; float a = (float) Math.sqrt(vx * vx + vy * vy); // only if not cur segment crosses edge if (edge < (1 << 4)) { vx /= a; vy /= a; // add additional segments if possible for (int j = i + 4; j < pos + len; j += 2) { float nextX = coordinates[j + 0]; float nextY = coordinates[j + 1]; //if ((clip = clipper.clipNext(nextX, nextY)) != 0) { // if (clip < 0) { // curX = clipper.out[0]; // curY = clipper.out[1]; // // TODO break when cur has changed // nextX = clipper.out[2]; // nextY = clipper.out[3]; // } //} float wx = nextX - curX; float wy = nextY - curY; if (wx == 0 && wy == 0) continue; float area = GeometryUtils.area(prevX, prevY, curX, curY, nextX, nextY); if (area > 1000) { //log.debug("b: " + string + " " + area ); break; } a = (float) Math.sqrt(wx * wx + wy * wy); wx /= a; wy /= a; // avoid adding short segments that add much area if (area / 2 > a * a) { //log.debug("a: " +string + " " + area + " " + a*a); break; } float ux = vx + wx; float uy = vy + wy; float diff = wx * uy - wy * ux; // maximum angle between segments if (diff > 0.1 || diff < -0.1) { //log.debug("c: " + string + " " + area ); break; } curX = nextX; curY = nextY; last = j - 2; //if (clip < 0) { // if (nextX == min) // edge |= 1 << 4; // else if (nextX == max) // edge |= 1 << 5; // // if (nextY == min) // edge |= 1 << 6; // else if (nextY == max) // edge |= 1 << 7; //} } vx = curX - prevX; vy = curY - prevY; a = (float) Math.sqrt(vx * vx + vy * vy); } float segmentLength = a; if (edge == 0) { if (segmentLength < minWidth) { continue; } if (labelWidth < 0) { labelWidth = text.paint.measureText(string); } if (segmentLength < labelWidth * 0.50) { continue; } } else if (labelWidth < 0) { labelWidth = text.paint.measureText(string); } float x1, y1, x2, y2; if (prevX < curX) { x1 = prevX; y1 = prevY; x2 = curX; y2 = curY; } else { x1 = curX; y1 = curY; x2 = prevX; y2 = prevY; } TextItem n = TextItem.pool.get(); // link items together //if (t != null) { // t.n1 = n; // n.n2 = t; //} t = n; t.x = x1 + (x2 - x1) / 2f; t.y = y1 + (y2 - y1) / 2f; t.string = string; t.text = text; t.width = labelWidth; t.x1 = x1; t.y1 = y1; t.x2 = x2; t.y2 = y2; t.length = (short) segmentLength; t.edges = edge; ld.labels.push(t); i = last; } } private WayDecorator() { throw new IllegalStateException(); } }