boolean layout(PointLabel label, LabelIndex labels) { String text = label.getText(); Feature f = label.getFeature(); Geometry g = label.getGeometry(); Rule rule = label.getRule(); // get center in screen space Coordinate centroid = g.getCentroid().getCoordinate(); PointF anchor = tx.getWorldToCanvas().map(centroid); // apply offsets anchor.x += rule.number(f, TEXT_DX, 0f); anchor.y += rule.number(f, TEXT_DY, 0f); Paint p = label.get(Paint.class, Paint.class); // compute bounds of this label Rect b = new Rect(); p.getTextBounds(text, 0, text.length(), b); // padding float padding = rule.number(f, TEXT_MIN_PADDING, 0f); if (padding > 0f) { b = expand(b, padding); } // label.setAnchor(new Coordinate(center.x,center.y)); // label.setBox(envelope(rectFromBottomLeft(center, b.width(), b.height()))); RectF c = new RectF(b); tx.getCanvasToWorld().mapRect(c); centroid = tx.getCanvasToWorld().map(anchor); label.setAnchor(centroid); RectF box = null; switch (p.getTextAlign()) { case LEFT: box = rectFromBottomLeft(point(centroid), c.width(), c.height()); break; case CENTER: box = rectFromBottomCenter(point(centroid), c.width(), c.height()); break; case RIGHT: box = rectFromBottomRight(point(centroid), c.width(), c.height()); break; } label.setBox(envelope(box)); return labels.insert(label); }
boolean layout(LineLabel label, LabelIndex labels) { String txt = label.getText(); Rule rule = label.getRule(); Feature f = label.getFeature(); Geometry g = label.getGeometry(); LineString line = null; if (g instanceof MultiLineString) { // TODO: handle multiple lines if (g.getNumGeometries() == 1) { line = (LineString) g.getGeometryN(0); } } else { line = (LineString) g; } if (line == null) { return false; } Paint p = label.get(Paint.class, Paint.class); // compute the bounds of the label with no rotation Rect r = new Rect(); p.getTextBounds(txt, 0, txt.length(), r); // map it to world coordinates RectF bounds = new RectF(r); tx.getCanvasToWorld().mapRect(bounds); // ignore label if its too long for the line if (line.getLength() < bounds.width()) { // ignore this label return false; } // reverse if (line.getPointN(0).getX() > line.getPointN(line.getNumPoints() - 1).getX()) { line = (LineString) line.reverse(); } // compute width of individual letters float[] widths = new float[txt.length()]; p.getTextWidths(txt, widths); // map the widths to world space float sum = 0; for (int i = 0; i < widths.length; i++) { RectF s = new RectF(0, 0, widths[i], 1); tx.getCanvasToWorld().mapRect(s); widths[i] = s.width(); sum += s.width(); } // TODO: properly figure out spacing between letters float space = tx.getCanvasToWorld().mapRadius(1); // allowable angle change in consecutive characters double maxAngleDelta = rule.number(f, TEXT_MAX_CHAR_ANGLE_DELTA, DEFAULT_MAX_ANGLE_CHAR_DELTA); // // sample points along the line for letters // List<LineSegment> path = new ArrayList<LineSegment>(); LineSampler sampler = new LineSampler(line.getCoordinates()); for (int i = 0; i < txt.length(); i++) { // get next point Coordinate c1 = sampler.sample(); // advance by width of letter sampler.advance(widths[i]); // get point for end of letter Coordinate c2 = sampler.sample(); if (c1 == null || c2 == null) { // ran out of room return false; } LineSegment seg = new LineSegment(c1, c2); // check angle made with previous segment if (i > 0) { LineSegment prev = path.get(i - 1); if (Math.abs(angle(seg) - angle(prev)) > maxAngleDelta) { return false; } } path.add(seg); sampler.advance(space); } label.setPath(path); label.setShape(toShape(path, bounds.height())); return labels.insert(label); }