Changeset 32394 in osm for applications/editors/josm/plugins/seachart/src/render/Renderer.java
- Timestamp:
- 2016-06-24T03:48:12+02:00 (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/seachart/src/render/Renderer.java
r32380 r32394 10 10 package render; 11 11 12 import java.awt.*; 13 import java.awt.font.*; 14 import java.awt.geom.*; 15 import java.awt.image.*; 16 import java.util.*; 17 18 import s57.S57val.*; 12 import java.awt.BasicStroke; 13 import java.awt.Color; 14 import java.awt.Font; 15 import java.awt.Graphics2D; 16 import java.awt.Rectangle; 17 import java.awt.RenderingHints; 18 import java.awt.TexturePaint; 19 import java.awt.font.FontRenderContext; 20 import java.awt.font.GlyphVector; 21 import java.awt.geom.AffineTransform; 22 import java.awt.geom.Arc2D; 23 import java.awt.geom.Ellipse2D; 24 import java.awt.geom.GeneralPath; 25 import java.awt.geom.Line2D; 26 import java.awt.geom.Path2D; 27 import java.awt.geom.Point2D; 28 import java.awt.geom.Rectangle2D; 29 import java.awt.geom.RoundRectangle2D; 30 import java.awt.image.AffineTransformOp; 31 import java.awt.image.BufferedImage; 32 import java.util.ArrayList; 33 19 34 import s57.S57map; 20 import s57.S57map.*; 35 import s57.S57map.GeomIterator; 36 import s57.S57map.Pflag; 37 import s57.S57map.Snode; 38 import s57.S57val.UniHLU; 21 39 import symbols.Areas; 22 40 import symbols.Symbols; 23 import symbols.Symbols.*; 41 import symbols.Symbols.Caption; 42 import symbols.Symbols.Delta; 43 import symbols.Symbols.Form; 44 import symbols.Symbols.Handle; 45 import symbols.Symbols.Instr; 46 import symbols.Symbols.LineStyle; 47 import symbols.Symbols.Scheme; 48 import symbols.Symbols.SubSymbol; 49 import symbols.Symbols.Symbol; 24 50 25 51 public class Renderer { 26 52 27 public static final double symbolScale[] = { 256.0, 128.0, 64.0, 32.0, 16.0, 8.0, 4.0, 2.0, 1.0, 0.61, 0.372, 0.227, 0.138, 0.0843, 0.0514, 0.0313, 0.0191, 0.0117, 0.007 }; 28 29 public enum LabelStyle { NONE, RRCT, RECT, ELPS, CIRC, VCLR, PCLR, HCLR } 30 31 static ChartContext context; 32 static S57map map; 33 static double sScale; 34 static Graphics2D g2; 35 static int zoom; 36 37 public static void reRender(Graphics2D g, Rectangle rect, int z, double factor, S57map m, ChartContext c) { 38 g2 = g; 39 zoom = z; 40 context = c; 41 map = m; 42 sScale = symbolScale[zoom] * factor; 43 if (map != null) { 44 if (context.clip()) { 45 Point2D tl = context.getPoint(map.new Snode(map.bounds.maxlat, map.bounds.minlon)); 46 Point2D br = context.getPoint(map.new Snode(map.bounds.minlat, map.bounds.maxlon)); 47 g2.clip(new Rectangle2D.Double(tl.getX(), tl.getY(), (br.getX() - tl.getX()), (br.getY() - tl.getY()))); 48 } 49 g2.setBackground(context.background(map)); 50 g2.clearRect(rect.x, rect.y, rect.width, rect.height); 51 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 52 g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_GASP); 53 g2.setStroke(new BasicStroke(0, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER)); 54 Rules.rules(); 55 } 56 } 57 58 public static void symbol(Symbol symbol) { 59 Point2D point = context.getPoint(Rules.feature.geom.centre); 60 Symbols.drawSymbol(g2, symbol, sScale, point.getX(), point.getY(), null, null); 61 } 62 public static void symbol(Symbol symbol, Scheme scheme) { 63 Point2D point = context.getPoint(Rules.feature.geom.centre); 64 Symbols.drawSymbol(g2, symbol, sScale, point.getX(), point.getY(), scheme, null); 65 } 66 public static void symbol(Symbol symbol, Delta delta) { 67 Point2D point = context.getPoint(Rules.feature.geom.centre); 68 Symbols.drawSymbol(g2, symbol, sScale, point.getX(), point.getY(), null, delta); 69 } 70 public static void symbol(Symbol symbol, Scheme scheme, Delta delta) { 71 Point2D point = context.getPoint(Rules.feature.geom.centre); 72 Symbols.drawSymbol(g2, symbol, sScale, point.getX(), point.getY(), scheme, delta); 73 } 74 75 public static void cluster(ArrayList<Symbol> symbols) { 76 Rectangle2D.Double bbox = null; 77 if (symbols.size() > 4) { 78 for (Instr instr : symbols.get(0)) { 79 if (instr.type == Form.BBOX) { 80 bbox = (Rectangle2D.Double) instr.params; 81 break; 82 } 83 } 84 if (bbox == null) return; 85 } 86 switch (symbols.size()) { 87 case 1: 88 symbol(symbols.get(0), new Delta(Handle.CC, new AffineTransform())); 89 break; 90 case 2: 91 symbol(symbols.get(0), new Delta(Handle.RC, new AffineTransform())); 92 symbol(symbols.get(1), new Delta(Handle.LC, new AffineTransform())); 93 break; 94 case 3: 95 symbol(symbols.get(0), new Delta(Handle.BC, new AffineTransform())); 96 symbol(symbols.get(1), new Delta(Handle.TR, new AffineTransform())); 97 symbol(symbols.get(2), new Delta(Handle.TL, new AffineTransform())); 98 break; 99 case 4: 100 symbol(symbols.get(0), new Delta(Handle.BR, new AffineTransform())); 101 symbol(symbols.get(1), new Delta(Handle.BL, new AffineTransform())); 102 symbol(symbols.get(2), new Delta(Handle.TR, new AffineTransform())); 103 symbol(symbols.get(3), new Delta(Handle.TL, new AffineTransform())); 104 break; 105 case 5: 106 symbol(symbols.get(0), new Delta(Handle.BR, new AffineTransform())); 107 symbol(symbols.get(1), new Delta(Handle.BL, new AffineTransform())); 108 symbol(symbols.get(2), new Delta(Handle.TR, AffineTransform.getTranslateInstance(-bbox.width/2, 0))); 109 symbol(symbols.get(3), new Delta(Handle.TC, new AffineTransform())); 110 symbol(symbols.get(4), new Delta(Handle.TL, AffineTransform.getTranslateInstance(bbox.width/2, 0))); 111 break; 112 case 6: 113 symbol(symbols.get(0), new Delta(Handle.BR, AffineTransform.getTranslateInstance(-bbox.width/2, 0))); 114 symbol(symbols.get(1), new Delta(Handle.BC, new AffineTransform())); 115 symbol(symbols.get(2), new Delta(Handle.BL, AffineTransform.getTranslateInstance(bbox.width/2, 0))); 116 symbol(symbols.get(3), new Delta(Handle.TR, AffineTransform.getTranslateInstance(-bbox.width/2, 0))); 117 symbol(symbols.get(4), new Delta(Handle.TC, new AffineTransform())); 118 symbol(symbols.get(5), new Delta(Handle.TL, AffineTransform.getTranslateInstance(bbox.width/2, 0))); 119 break; 120 case 7: 121 symbol(symbols.get(0), new Delta(Handle.BC, AffineTransform.getTranslateInstance(0, -bbox.height/2))); 122 symbol(symbols.get(1), new Delta(Handle.RC, AffineTransform.getTranslateInstance(-bbox.width/2, 0))); 123 symbol(symbols.get(2), new Delta(Handle.CC, new AffineTransform())); 124 symbol(symbols.get(3), new Delta(Handle.LC, AffineTransform.getTranslateInstance(bbox.width/2, 0))); 125 symbol(symbols.get(4), new Delta(Handle.TR, AffineTransform.getTranslateInstance(-bbox.width/2, bbox.height/2))); 126 symbol(symbols.get(5), new Delta(Handle.TC, AffineTransform.getTranslateInstance(0, bbox.height/2))); 127 symbol(symbols.get(6), new Delta(Handle.TL, AffineTransform.getTranslateInstance(bbox.width/2, bbox.height/2))); 128 break; 129 case 8: 130 symbol(symbols.get(0), new Delta(Handle.BR, AffineTransform.getTranslateInstance(0, -bbox.height/2))); 131 symbol(symbols.get(1), new Delta(Handle.BL, AffineTransform.getTranslateInstance(0, -bbox.height/2))); 132 symbol(symbols.get(2), new Delta(Handle.RC, AffineTransform.getTranslateInstance(-bbox.width/2, 0))); 133 symbol(symbols.get(3), new Delta(Handle.CC, new AffineTransform())); 134 symbol(symbols.get(4), new Delta(Handle.LC, AffineTransform.getTranslateInstance(bbox.width/2, 0))); 135 symbol(symbols.get(5), new Delta(Handle.TR, AffineTransform.getTranslateInstance(-bbox.width/2, bbox.height/2))); 136 symbol(symbols.get(6), new Delta(Handle.TC, AffineTransform.getTranslateInstance(0, bbox.height/2))); 137 symbol(symbols.get(7), new Delta(Handle.TL, AffineTransform.getTranslateInstance(bbox.width/2, bbox.height/2))); 138 break; 139 case 9: 140 symbol(symbols.get(0), new Delta(Handle.BR, AffineTransform.getTranslateInstance(-bbox.width/2, -bbox.height/2))); 141 symbol(symbols.get(1), new Delta(Handle.BC, AffineTransform.getTranslateInstance(0, -bbox.height/2))); 142 symbol(symbols.get(2), new Delta(Handle.BL, AffineTransform.getTranslateInstance(bbox.width/2, -bbox.height/2))); 143 symbol(symbols.get(3), new Delta(Handle.RC, AffineTransform.getTranslateInstance(-bbox.width/2, 0))); 144 symbol(symbols.get(4), new Delta(Handle.CC, new AffineTransform())); 145 symbol(symbols.get(5), new Delta(Handle.LC, AffineTransform.getTranslateInstance(bbox.width/2, 0))); 146 symbol(symbols.get(6), new Delta(Handle.TR, AffineTransform.getTranslateInstance(-bbox.width/2, bbox.height/2))); 147 symbol(symbols.get(7), new Delta(Handle.TC, AffineTransform.getTranslateInstance(0, bbox.height/2))); 148 symbol(symbols.get(8), new Delta(Handle.TL, AffineTransform.getTranslateInstance(bbox.width/2, bbox.height/2))); 149 break; 150 } 151 } 152 153 private static Rectangle2D.Double symbolSize(Symbol symbol) { 154 Symbol ssymb = symbol; 155 while (ssymb != null) { 156 for (Instr item : symbol) { 157 if (item.type == Form.BBOX) { 158 return (Rectangle2D.Double) item.params; 159 } 160 if (item.type == Form.SYMB) { 161 ssymb = ((SubSymbol) item.params).instr; 162 break; 163 } 164 } 165 if (ssymb == symbol) 166 break; 167 } 168 return null; 169 } 170 171 public static void lineSymbols(Symbol prisymb, double space, Symbol secsymb, Symbol tersymb, int ratio, Color col) { 172 if ((Rules.feature.geom.prim == Pflag.NOSP) || (Rules.feature.geom.prim == Pflag.POINT)) 173 return; 174 Rectangle2D.Double prect = symbolSize(prisymb); 175 Rectangle2D.Double srect = symbolSize(secsymb); 176 Rectangle2D.Double trect = symbolSize(tersymb); 177 if (srect == null) 178 ratio = 0; 179 if (prect != null) { 180 double psize = Math.abs(prect.getY()) * sScale; 181 double ssize = (srect != null) ? Math.abs(srect.getY()) * sScale : 0; 182 double tsize = (trect != null) ? Math.abs(srect.getY()) * sScale : 0; 183 Point2D prev = new Point2D.Double(); 184 Point2D next = new Point2D.Double(); 185 Point2D curr = new Point2D.Double(); 186 Point2D succ = new Point2D.Double(); 187 boolean gap = true; 188 boolean piv = false; 189 double len = 0; 190 double angle = 0; 191 int stcount = ratio; 192 boolean stflag = false; 193 Symbol symbol = prisymb; 194 GeomIterator git = map.new GeomIterator(Rules.feature.geom); 195 while (git.hasComp()) { 196 git.nextComp(); 197 boolean first = true; 198 while (git.hasEdge()) { 199 git.nextEdge(); 200 while (git.hasNode()) { 201 Snode node = git.next(); 202 if (node == null) continue; 203 prev = next; 204 next = context.getPoint(node); 205 angle = Math.atan2(next.getY() - prev.getY(), next.getX() - prev.getX()); 206 piv = true; 207 if (first) { 208 curr = succ = next; 209 gap = (space > 0); 210 stcount = ratio - 1; 211 symbol = prisymb; 212 len = gap ? psize * space * 0.5 : psize; 213 first = false; 214 } else { 215 while (curr.distance(next) >= len) { 216 if (piv) { 217 double rem = len; 218 double s = prev.distance(next); 219 double p = curr.distance(prev); 220 if ((s > 0) && (p > 0)) { 221 double n = curr.distance(next); 222 double theta = Math.acos((s * s + p * p - n * n) / 2 / s / p); 223 double phi = Math.asin(p / len * Math.sin(theta)); 224 rem = len * Math.sin(Math.PI - theta - phi) / Math.sin(theta); 225 } 226 succ = new Point2D.Double(prev.getX() + (rem * Math.cos(angle)), prev.getY() + (rem * Math.sin(angle))); 227 piv = false; 228 } else { 229 succ = new Point2D.Double(curr.getX() + (len * Math.cos(angle)), curr.getY() + (len * Math.sin(angle))); 230 } 231 if (!gap) { 232 Symbols.drawSymbol(g2, symbol, sScale, curr.getX(), curr.getY(), new Scheme(col), 233 new Delta(Handle.BC, AffineTransform.getRotateInstance(Math.atan2((succ.getY() - curr.getY()), (succ.getX() - curr.getX())) + Math.toRadians(90)))); 234 } 235 if (space > 0) 236 gap = !gap; 237 curr = succ; 238 len = gap ? (psize * space) : (--stcount == 0) ? (stflag ? tsize : ssize) : psize; 239 if (stcount == 0) { 240 symbol = stflag ? tersymb : secsymb; 241 if (trect != null) 242 stflag = !stflag; 243 stcount = ratio; 244 } else { 245 symbol = prisymb; 246 } 247 } 248 } 249 } 250 } 251 } 252 } 253 } 254 255 public static void lineVector(LineStyle style) { 256 Path2D.Double p = new Path2D.Double(); 257 p.setWindingRule(GeneralPath.WIND_EVEN_ODD); 258 Point2D point; 259 GeomIterator git = map.new GeomIterator(Rules.feature.geom); 260 while (git.hasComp()) { 261 git.nextComp(); 262 boolean first = true; 263 while (git.hasEdge()) { 264 git.nextEdge(); 265 point = context.getPoint(git.next()); 266 if (first) { 267 p.moveTo(point.getX(), point.getY()); 268 first = false; 269 } else { 270 p.lineTo(point.getX(), point.getY()); 271 } 272 while (git.hasNode()) { 273 Snode node = git.next(); 274 if (node == null) continue; 275 point = context.getPoint(node); 276 p.lineTo(point.getX(), point.getY()); 277 } 278 } 279 } 280 if ((style.fill != null) && (Rules.feature.geom.prim == Pflag.AREA)) { 281 g2.setPaint(style.fill); 282 g2.fill(p); 283 } 284 if (style.line != null) { 285 if (style.dash != null) { 286 float[] dash = new float[style.dash.length]; 287 System.arraycopy(style.dash, 0, dash, 0, style.dash.length); 288 for (int i = 0; i < style.dash.length; i++) { 289 dash[i] *= (float) sScale; 290 } 291 g2.setStroke(new BasicStroke((float) (style.width * sScale), BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 1, dash, 0)); 292 } else { 293 g2.setStroke(new BasicStroke((float) (style.width * sScale), BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); 294 } 295 g2.setPaint(style.line); 296 g2.draw(p); 297 } 298 } 299 300 public static void lineCircle(LineStyle style, double radius, UniHLU units) { 301 switch (units) { 302 case HLU_FEET: 303 radius /= 6076; 304 break; 305 case HLU_KMTR: 306 radius /= 1.852; 307 break; 308 case HLU_HMTR: 309 radius /= 18.52; 310 break; 311 case HLU_SMIL: 312 radius /= 1.15078; 313 break; 314 case HLU_NMIL: 315 break; 316 default: 317 radius /= 1852; 318 break; 319 } 320 radius *= context.mile(Rules.feature); 321 Symbol circle = new Symbol(); 322 if (style.fill != null) { 323 circle.add(new Instr(Form.FILL, style.fill)); 324 circle.add(new Instr(Form.RSHP, new Ellipse2D.Double(-radius,-radius,radius*2,radius*2))); 325 } 326 circle.add(new Instr(Form.FILL, style.line)); 327 circle.add(new Instr(Form.STRK, new BasicStroke(style.width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1, style.dash, 0))); 328 circle.add(new Instr(Form.ELPS, new Ellipse2D.Double(-radius,-radius,radius*2,radius*2))); 329 Point2D point = context.getPoint(Rules.feature.geom.centre); 330 Symbols.drawSymbol(g2, circle, 1, point.getX(), point.getY(), null, null); 331 } 332 333 public static void fillPattern(BufferedImage image) { 334 Path2D.Double p = new Path2D.Double(); 335 p.setWindingRule(GeneralPath.WIND_EVEN_ODD); 336 Point2D point; 337 switch (Rules.feature.geom.prim) { 338 case POINT: 339 point = context.getPoint(Rules.feature.geom.centre); 340 g2.drawImage(image, new AffineTransformOp(AffineTransform.getScaleInstance(sScale, sScale), AffineTransformOp.TYPE_NEAREST_NEIGHBOR), 341 (int)(point.getX() - (50 * sScale)), (int)(point.getY() - (50 * sScale))); 342 break; 343 case AREA: 344 GeomIterator git = map.new GeomIterator(Rules.feature.geom); 345 while (git.hasComp()) { 346 git.nextComp(); 347 boolean newComp = true; 348 while (git.hasEdge()) { 349 git.nextEdge(); 350 point = context.getPoint(git.next()); 351 if (newComp) { 352 p.moveTo(point.getX(), point.getY()); 353 newComp = false; 354 } else { 355 p.lineTo(point.getX(), point.getY()); 356 } 357 while (git.hasNode()) { 358 Snode node = git.next(); 359 if (node == null) continue; 360 point = context.getPoint(node); 361 p.lineTo(point.getX(), point.getY()); 362 } 363 } 364 } 365 g2.setPaint(new TexturePaint(image, new Rectangle(0, 0, 1 + (int)(300 * sScale), 1 + (int)(300 * sScale)))); 366 g2.fill(p); 367 break; 368 default: 369 break; 370 } 371 } 372 373 public static void labelText(String str, Font font, Color tc) { 374 labelText(str, font, tc, LabelStyle.NONE, null, null, null); 375 } 376 public static void labelText(String str, Font font, Color tc, Delta delta) { 377 labelText(str, font, tc, LabelStyle.NONE, null, null, delta); 378 } 379 public static void labelText(String str, Font font, Color tc, LabelStyle style, Color fg) { 380 labelText(str, font, tc, style, fg, null, null); 381 } 382 public static void labelText(String str, Font font, Color tc, LabelStyle style, Color fg, Color bg) { 383 labelText(str, font, tc, style, fg, bg, null); 384 } 385 public static void labelText(String str, Font font, Color tc, LabelStyle style, Color fg, Delta delta) { 386 labelText(str, font, tc, style, fg, null, delta); 387 } 388 public static void labelText(String str, Font font, Color tc, LabelStyle style, Color fg, Color bg, Delta delta) { 389 if (delta == null) delta = new Delta(Handle.CC); 390 if (bg == null) bg = new Color(0x00000000, true); 391 if ((str == null) || (str.isEmpty())) str = " "; 392 FontRenderContext frc = g2.getFontRenderContext(); 393 GlyphVector gv = font.deriveFont((float)(font.getSize())).createGlyphVector(frc, str.equals(" ") ? "M" : str); 394 Rectangle2D bounds = gv.getVisualBounds(); 395 double width = bounds.getWidth(); 396 double height = bounds.getHeight(); 397 Symbol label = new Symbol(); 398 double lx, ly, tx, ty; 399 switch (style) { 400 case RRCT: 401 width += height * 1.0; 402 height *= 1.5; 403 if (width < height) width = height; 404 lx = -width / 2; 405 ly = -height / 2; 406 tx = lx + (height * 0.34); 407 ty = ly + (height * 0.17); 408 label.add(new Instr(Form.BBOX, new Rectangle2D.Double(lx,ly,width,height))); 409 label.add(new Instr(Form.FILL, bg)); 410 label.add(new Instr(Form.RSHP, new RoundRectangle2D.Double(lx,ly,width,height,height,height))); 411 label.add(new Instr(Form.FILL, fg)); 412 label.add(new Instr(Form.STRK, new BasicStroke(1 + (int)(height/10), BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER))); 413 label.add(new Instr(Form.RRCT, new RoundRectangle2D.Double(lx,ly,width,height,height,height))); 414 break; 415 case VCLR: 416 width += height * 1.0; 417 height *= 2.0; 418 if (width < height) width = height; 419 lx = -width / 2; 420 ly = -height / 2; 421 tx = lx + (height * 0.27); 422 ty = ly + (height * 0.25); 423 label.add(new Instr(Form.BBOX, new Rectangle2D.Double(lx,ly,width,height))); 424 label.add(new Instr(Form.FILL, bg)); 425 label.add(new Instr(Form.RSHP, new RoundRectangle2D.Double(lx,ly,width,height,height,height))); 426 label.add(new Instr(Form.FILL, fg)); 427 int sw = 1 + (int)(height/10); 428 double po = sw / 2; 429 label.add(new Instr(Form.STRK, new BasicStroke(sw, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER))); 430 Path2D.Double p = new Path2D.Double(); p.moveTo(-height*0.2,-ly-po); p.lineTo(height*0.2,-ly-po); p.moveTo(0,-ly-po); p.lineTo(0,-ly-po-(height*0.15)); 431 p.moveTo(-height*0.2,ly+po); p.lineTo((height*0.2),ly+po); p.moveTo(0,ly+po); p.lineTo(0,ly+po+(height*0.15)); 432 label.add(new Instr(Form.PLIN, p)); 433 break; 434 case PCLR: 435 width += height * 1.0; 436 height *= 2.0; 437 if (width < height) width = height; 438 lx = -width / 2; 439 ly = -height / 2; 440 tx = lx + (height * 0.27); 441 ty = ly + (height * 0.25); 442 label.add(new Instr(Form.BBOX, new Rectangle2D.Double(lx,ly,width,height))); 443 label.add(new Instr(Form.FILL, bg)); 444 label.add(new Instr(Form.RSHP, new RoundRectangle2D.Double(lx,ly,width,height,height,height))); 445 label.add(new Instr(Form.FILL, fg)); 446 sw = 1 + (int)(height/10); 447 po = sw / 2; 448 label.add(new Instr(Form.STRK, new BasicStroke(sw, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER))); 449 p = new Path2D.Double(); p.moveTo(-height*0.2,-ly-po); p.lineTo(height*0.2,-ly-po); p.moveTo(0,-ly-po); p.lineTo(0,-ly-po-(height*0.15)); 450 p.moveTo(-height*0.2,ly+po); p.lineTo((height*0.2),ly+po); p.moveTo(0,ly+po); p.lineTo(0,ly+po+(height*0.15)); 451 label.add(new Instr(Form.PLIN, p)); 452 label.add(new Instr(Form.SYMB, new Symbols.SubSymbol(Areas.CableFlash, 1, 0, 0, null, new Delta(Handle.CC, new AffineTransform(0,-1,1,0,-width/2,0))))); 453 label.add(new Instr(Form.SYMB, new Symbols.SubSymbol(Areas.CableFlash, 1, 0, 0, null, new Delta(Handle.CC, new AffineTransform(0,-1,1,0,width/2,0))))); 454 break; 455 case HCLR: 456 width += height * 1.5; 457 height *= 1.5; 458 if (width < height) width = height; 459 lx = -width / 2; 460 ly = -height / 2; 461 tx = lx + (height * 0.5); 462 ty = ly + (height * 0.17); 463 label.add(new Instr(Form.BBOX, new Rectangle2D.Double(lx,ly,width,height))); 464 label.add(new Instr(Form.FILL, bg)); 465 label.add(new Instr(Form.RSHP, new RoundRectangle2D.Double(lx,ly,width,height,height,height))); 466 label.add(new Instr(Form.FILL, fg)); 467 sw = 1 + (int)(height/10); 468 double vo = height / 4; 469 label.add(new Instr(Form.STRK, new BasicStroke(sw, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER))); 470 p = new Path2D.Double(); p.moveTo(-width*0.4-sw,-ly-vo); p.lineTo(-width*0.4-sw,ly+vo); p.moveTo(-width*0.4-sw,0); p.lineTo(-width*0.4+sw,0); 471 p.moveTo(width*0.4+sw,-ly-vo); p.lineTo(width*0.4+sw,ly+vo); p.moveTo(width*0.4-sw,0); p.lineTo(width*0.4+sw,0); 472 label.add(new Instr(Form.PLIN, p)); 473 break; 474 default: 475 lx = -width / 2; 476 ly = -height / 2; 477 tx = lx; 478 ty = ly; 479 label.add(new Instr(Form.BBOX, new Rectangle2D.Double(lx,ly,width,height))); 480 break; 481 } 482 label.add(new Instr(Form.TEXT, new Caption(str, font, tc, new Delta(Handle.TL, AffineTransform.getTranslateInstance(tx, ty))))); 483 Point2D point = context.getPoint(Rules.feature.geom.centre); 484 Symbols.drawSymbol(g2, label, sScale, point.getX(), point.getY(), null, delta); 485 } 486 487 public static void lineText(String str, Font font, Color colour, double dy) { 488 if (!str.isEmpty()) { 489 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 490 g2.setPaint(colour); 491 FontRenderContext frc = g2.getFontRenderContext(); 492 GlyphVector gv = font.deriveFont(font.getSize2D() * (float) sScale).createGlyphVector(frc, str); 493 double width = gv.getVisualBounds().getWidth(); 494 double height = gv.getVisualBounds().getHeight(); 495 double offset = (Rules.feature.geom.length * context.mile(Rules.feature) - width) / 2; 496 if (offset > 0) { 497 Point2D before = null; 498 Point2D after = null; 499 ArrayList<Point2D> between = new ArrayList<>(); 500 Point2D prev = null; 501 Point2D next = null; 502 double length = 0; 503 double lb = 0; 504 double la = 0; 505 GeomIterator git = map.new GeomIterator(Rules.feature.geom); 506 if (git.hasComp()) { 507 git.nextComp(); 508 while (git.hasEdge()) { 509 git.nextEdge(); 510 while (git.hasNode()) { 511 Snode node = git.next(); 512 if (node == null) 513 continue; 514 prev = next; 515 next = context.getPoint(node); 516 if (prev != null) 517 length += Math.sqrt(Math.pow((next.getX() - prev.getX()), 2) + Math.pow((next.getY() - prev.getY()), 2)); 518 if (length < offset) { 519 before = next; 520 lb = la = length; 521 } else if (after == null) { 522 if (length > (offset + width)) { 523 after = next; 524 la = length; 525 break; 526 } else { 527 between.add(next); 528 } 529 } 530 } 531 if (after != null) 532 break; 533 } 534 } 535 if (after != null) { 536 double angle = Math.atan2((after.getY() - before.getY()), (after.getX() - before.getX())); 537 double rotate = Math.abs(angle) < (Math.PI / 2) ? angle : angle + Math.PI; 538 Point2D mid = new Point2D.Double((before.getX() + after.getX()) / 2, (before.getY() + after.getY()) / 2); 539 Point2D centre = context.getPoint(Rules.feature.geom.centre); 540 AffineTransform pos = AffineTransform.getTranslateInstance(-dy * Math.sin(rotate), dy * Math.cos(rotate)); 541 pos.rotate(rotate); 542 pos.translate((mid.getX() - centre.getX()), (mid.getY() - centre.getY())); 543 Symbol label = new Symbol(); 544 label.add(new Instr(Form.BBOX, new Rectangle2D.Double((-width / 2), (-height), width, height))); 545 label.add(new Instr(Form.TEXT, new Caption(str, font, colour, new Delta(Handle.BC)))); 546 Symbols.drawSymbol(g2, label, sScale, centre.getX(), centre.getY(), null, new Delta(Handle.BC, pos)); 547 } 548 } 549 } 550 } 551 552 public static void lightSector(Color col1, Color col2, double radius, double s1, double s2, Double dir, String str) { 553 if ((zoom >= 16) && (radius > 0.2)) { 554 radius /= (Math.pow(2, zoom-15)); 555 } 556 double mid = (((s1 + s2) / 2) + (s1 > s2 ? 180 : 0)) % 360; 557 g2.setStroke(new BasicStroke((float) (3.0 * sScale), BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 1, new float[] {20 * (float)sScale, 20 * (float)sScale}, 0)); 558 g2.setPaint(Color.black); 559 Point2D.Double centre = (Point2D.Double) context.getPoint(Rules.feature.geom.centre); 560 double radial = radius * context.mile(Rules.feature); 561 if (dir != null) { 562 g2.draw(new Line2D.Double(centre.x, centre.y, centre.x - radial * Math.sin(Math.toRadians(dir)), centre.y + radial * Math.cos(Math.toRadians(dir)))); 563 } else { 564 if ((s1 != 0.0) || (s2 != 360.0)) { 565 g2.draw(new Line2D.Double(centre.x, centre.y, centre.x - radial * Math.sin(Math.toRadians(s1)), centre.y + radial * Math.cos(Math.toRadians(s1)))); 566 g2.draw(new Line2D.Double(centre.x, centre.y, centre.x - radial * Math.sin(Math.toRadians(s2)), centre.y + radial * Math.cos(Math.toRadians(s2)))); 567 } 568 } 569 double arcWidth = 10.0 * sScale; 570 g2.setStroke(new BasicStroke((float)arcWidth, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1)); 571 g2.setPaint(col1); 572 g2.draw(new Arc2D.Double(centre.x - radial, centre.y - radial, 2 * radial, 2 * radial, -(s1 + 90), ((s1 < s2) ? (s1 - s2) : (s1 - s2 - 360)), Arc2D.OPEN)); 573 if (col2 != null) { 574 g2.setPaint(col2); 575 g2.draw(new Arc2D.Double(centre.x - radial + arcWidth, centre.y - radial + arcWidth, 2 * (radial - arcWidth), 2 * (radial - arcWidth), -(s1 + 90), ((s1 < s2) ? (s1 - s2) : (s1 - s2 - 360)), Arc2D.OPEN)); 576 } 577 if ((str != null) && (!str.isEmpty())) { 578 Font font = new Font("Arial", Font.PLAIN, 40); 579 double arc = (s2 > s1) ? (s2 - s1) : (s2 - s1 + 360); 580 double awidth = (Math.toRadians(arc) * radial); 581 boolean hand = ((mid > 270) || (mid < 90)); 582 double phi = Math.toRadians(mid); 583 radial += 30 * sScale; 584 AffineTransform at = AffineTransform.getTranslateInstance(-radial * Math.sin(phi) / sScale, radial * Math.cos(phi) / sScale); 585 if ((font.getSize() * sScale * str.length()) < awidth) { 586 at.rotate(Math.toRadians(mid + (hand ? 0 : 180))); 587 labelText(str, font, Color.black, new Delta(Handle.CC, at)); 588 } else if ((font.getSize() * sScale) < awidth) { 589 hand = (mid < 180); 590 at.rotate(Math.toRadians(mid + (hand ? -90 : 90))); 591 labelText(str, font, Color.black, hand ? new Delta(Handle.RC, at) : new Delta(Handle.LC, at)); 592 } 593 if (dir != null) { 594 font = new Font("Arial", Font.PLAIN, 30); 595 str = dir + "°"; 596 hand = (dir > 180); 597 phi = Math.toRadians(dir + (hand ? -0.5 : 0.5)); 598 radial -= 70 * sScale; 599 at = AffineTransform.getTranslateInstance(-radial * Math.sin(phi) / sScale, radial * Math.cos(phi) / sScale); 600 at.rotate(Math.toRadians(dir + (hand ? 90 : -90))); 601 labelText(str, font, Color.black, hand ? new Delta(Handle.BR, at) : new Delta(Handle.BL, at)); 602 } 603 } 604 } 53 public static final double[] symbolScale = {256.0, 128.0, 64.0, 32.0, 16.0, 8.0, 4.0, 2.0, 1.0, 0.61, 0.372, 0.227, 0.138, 0.0843, 0.0514, 0.0313, 0.0191, 0.0117, 0.007 }; 54 55 public enum LabelStyle { NONE, RRCT, RECT, ELPS, CIRC, VCLR, PCLR, HCLR } 56 57 static ChartContext context; 58 static S57map map; 59 static double sScale; 60 static Graphics2D g2; 61 static int zoom; 62 63 public static void reRender(Graphics2D g, Rectangle rect, int z, double factor, S57map m, ChartContext c) { 64 g2 = g; 65 zoom = z; 66 context = c; 67 map = m; 68 sScale = symbolScale[zoom] * factor; 69 if (map != null) { 70 if (context.clip()) { 71 Point2D tl = context.getPoint(map.new Snode(map.bounds.maxlat, map.bounds.minlon)); 72 Point2D br = context.getPoint(map.new Snode(map.bounds.minlat, map.bounds.maxlon)); 73 g2.clip(new Rectangle2D.Double(tl.getX(), tl.getY(), (br.getX() - tl.getX()), (br.getY() - tl.getY()))); 74 } 75 g2.setBackground(context.background(map)); 76 g2.clearRect(rect.x, rect.y, rect.width, rect.height); 77 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 78 g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_GASP); 79 g2.setStroke(new BasicStroke(0, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER)); 80 Rules.rules(); 81 } 82 } 83 84 public static void symbol(Symbol symbol) { 85 Point2D point = context.getPoint(Rules.feature.geom.centre); 86 Symbols.drawSymbol(g2, symbol, sScale, point.getX(), point.getY(), null, null); 87 } 88 89 public static void symbol(Symbol symbol, Scheme scheme) { 90 Point2D point = context.getPoint(Rules.feature.geom.centre); 91 Symbols.drawSymbol(g2, symbol, sScale, point.getX(), point.getY(), scheme, null); 92 } 93 94 public static void symbol(Symbol symbol, Delta delta) { 95 Point2D point = context.getPoint(Rules.feature.geom.centre); 96 Symbols.drawSymbol(g2, symbol, sScale, point.getX(), point.getY(), null, delta); 97 } 98 99 public static void symbol(Symbol symbol, Scheme scheme, Delta delta) { 100 Point2D point = context.getPoint(Rules.feature.geom.centre); 101 Symbols.drawSymbol(g2, symbol, sScale, point.getX(), point.getY(), scheme, delta); 102 } 103 104 public static void cluster(ArrayList<Symbol> symbols) { 105 Rectangle2D.Double bbox = null; 106 if (symbols.size() > 4) { 107 for (Instr instr : symbols.get(0)) { 108 if (instr.type == Form.BBOX) { 109 bbox = (Rectangle2D.Double) instr.params; 110 break; 111 } 112 } 113 if (bbox == null) return; 114 } 115 switch (symbols.size()) { 116 case 1: 117 symbol(symbols.get(0), new Delta(Handle.CC, new AffineTransform())); 118 break; 119 case 2: 120 symbol(symbols.get(0), new Delta(Handle.RC, new AffineTransform())); 121 symbol(symbols.get(1), new Delta(Handle.LC, new AffineTransform())); 122 break; 123 case 3: 124 symbol(symbols.get(0), new Delta(Handle.BC, new AffineTransform())); 125 symbol(symbols.get(1), new Delta(Handle.TR, new AffineTransform())); 126 symbol(symbols.get(2), new Delta(Handle.TL, new AffineTransform())); 127 break; 128 case 4: 129 symbol(symbols.get(0), new Delta(Handle.BR, new AffineTransform())); 130 symbol(symbols.get(1), new Delta(Handle.BL, new AffineTransform())); 131 symbol(symbols.get(2), new Delta(Handle.TR, new AffineTransform())); 132 symbol(symbols.get(3), new Delta(Handle.TL, new AffineTransform())); 133 break; 134 case 5: 135 symbol(symbols.get(0), new Delta(Handle.BR, new AffineTransform())); 136 symbol(symbols.get(1), new Delta(Handle.BL, new AffineTransform())); 137 symbol(symbols.get(2), new Delta(Handle.TR, AffineTransform.getTranslateInstance(-bbox.width/2, 0))); 138 symbol(symbols.get(3), new Delta(Handle.TC, new AffineTransform())); 139 symbol(symbols.get(4), new Delta(Handle.TL, AffineTransform.getTranslateInstance(bbox.width/2, 0))); 140 break; 141 case 6: 142 symbol(symbols.get(0), new Delta(Handle.BR, AffineTransform.getTranslateInstance(-bbox.width/2, 0))); 143 symbol(symbols.get(1), new Delta(Handle.BC, new AffineTransform())); 144 symbol(symbols.get(2), new Delta(Handle.BL, AffineTransform.getTranslateInstance(bbox.width/2, 0))); 145 symbol(symbols.get(3), new Delta(Handle.TR, AffineTransform.getTranslateInstance(-bbox.width/2, 0))); 146 symbol(symbols.get(4), new Delta(Handle.TC, new AffineTransform())); 147 symbol(symbols.get(5), new Delta(Handle.TL, AffineTransform.getTranslateInstance(bbox.width/2, 0))); 148 break; 149 case 7: 150 symbol(symbols.get(0), new Delta(Handle.BC, AffineTransform.getTranslateInstance(0, -bbox.height/2))); 151 symbol(symbols.get(1), new Delta(Handle.RC, AffineTransform.getTranslateInstance(-bbox.width/2, 0))); 152 symbol(symbols.get(2), new Delta(Handle.CC, new AffineTransform())); 153 symbol(symbols.get(3), new Delta(Handle.LC, AffineTransform.getTranslateInstance(bbox.width/2, 0))); 154 symbol(symbols.get(4), new Delta(Handle.TR, AffineTransform.getTranslateInstance(-bbox.width/2, bbox.height/2))); 155 symbol(symbols.get(5), new Delta(Handle.TC, AffineTransform.getTranslateInstance(0, bbox.height/2))); 156 symbol(symbols.get(6), new Delta(Handle.TL, AffineTransform.getTranslateInstance(bbox.width/2, bbox.height/2))); 157 break; 158 case 8: 159 symbol(symbols.get(0), new Delta(Handle.BR, AffineTransform.getTranslateInstance(0, -bbox.height/2))); 160 symbol(symbols.get(1), new Delta(Handle.BL, AffineTransform.getTranslateInstance(0, -bbox.height/2))); 161 symbol(symbols.get(2), new Delta(Handle.RC, AffineTransform.getTranslateInstance(-bbox.width/2, 0))); 162 symbol(symbols.get(3), new Delta(Handle.CC, new AffineTransform())); 163 symbol(symbols.get(4), new Delta(Handle.LC, AffineTransform.getTranslateInstance(bbox.width/2, 0))); 164 symbol(symbols.get(5), new Delta(Handle.TR, AffineTransform.getTranslateInstance(-bbox.width/2, bbox.height/2))); 165 symbol(symbols.get(6), new Delta(Handle.TC, AffineTransform.getTranslateInstance(0, bbox.height/2))); 166 symbol(symbols.get(7), new Delta(Handle.TL, AffineTransform.getTranslateInstance(bbox.width/2, bbox.height/2))); 167 break; 168 case 9: 169 symbol(symbols.get(0), new Delta(Handle.BR, AffineTransform.getTranslateInstance(-bbox.width/2, -bbox.height/2))); 170 symbol(symbols.get(1), new Delta(Handle.BC, AffineTransform.getTranslateInstance(0, -bbox.height/2))); 171 symbol(symbols.get(2), new Delta(Handle.BL, AffineTransform.getTranslateInstance(bbox.width/2, -bbox.height/2))); 172 symbol(symbols.get(3), new Delta(Handle.RC, AffineTransform.getTranslateInstance(-bbox.width/2, 0))); 173 symbol(symbols.get(4), new Delta(Handle.CC, new AffineTransform())); 174 symbol(symbols.get(5), new Delta(Handle.LC, AffineTransform.getTranslateInstance(bbox.width/2, 0))); 175 symbol(symbols.get(6), new Delta(Handle.TR, AffineTransform.getTranslateInstance(-bbox.width/2, bbox.height/2))); 176 symbol(symbols.get(7), new Delta(Handle.TC, AffineTransform.getTranslateInstance(0, bbox.height/2))); 177 symbol(symbols.get(8), new Delta(Handle.TL, AffineTransform.getTranslateInstance(bbox.width/2, bbox.height/2))); 178 break; 179 } 180 } 181 182 private static Rectangle2D.Double symbolSize(Symbol symbol) { 183 Symbol ssymb = symbol; 184 while (ssymb != null) { 185 for (Instr item : symbol) { 186 if (item.type == Form.BBOX) { 187 return (Rectangle2D.Double) item.params; 188 } 189 if (item.type == Form.SYMB) { 190 ssymb = ((SubSymbol) item.params).instr; 191 break; 192 } 193 } 194 if (ssymb == symbol) 195 break; 196 } 197 return null; 198 } 199 200 public static void lineSymbols(Symbol prisymb, double space, Symbol secsymb, Symbol tersymb, int ratio, Color col) { 201 if ((Rules.feature.geom.prim == Pflag.NOSP) || (Rules.feature.geom.prim == Pflag.POINT)) 202 return; 203 Rectangle2D.Double prect = symbolSize(prisymb); 204 Rectangle2D.Double srect = symbolSize(secsymb); 205 Rectangle2D.Double trect = symbolSize(tersymb); 206 if (srect == null) 207 ratio = 0; 208 if (prect != null) { 209 double psize = Math.abs(prect.getY()) * sScale; 210 double ssize = (srect != null) ? Math.abs(srect.getY()) * sScale : 0; 211 double tsize = (trect != null) ? Math.abs(srect.getY()) * sScale : 0; 212 Point2D prev = new Point2D.Double(); 213 Point2D next = new Point2D.Double(); 214 Point2D curr = new Point2D.Double(); 215 Point2D succ = new Point2D.Double(); 216 boolean gap = true; 217 boolean piv = false; 218 double len = 0; 219 double angle = 0; 220 int stcount = ratio; 221 boolean stflag = false; 222 Symbol symbol = prisymb; 223 GeomIterator git = map.new GeomIterator(Rules.feature.geom); 224 while (git.hasComp()) { 225 git.nextComp(); 226 boolean first = true; 227 while (git.hasEdge()) { 228 git.nextEdge(); 229 while (git.hasNode()) { 230 Snode node = git.next(); 231 if (node == null) continue; 232 prev = next; 233 next = context.getPoint(node); 234 angle = Math.atan2(next.getY() - prev.getY(), next.getX() - prev.getX()); 235 piv = true; 236 if (first) { 237 curr = succ = next; 238 gap = (space > 0); 239 stcount = ratio - 1; 240 symbol = prisymb; 241 len = gap ? psize * space * 0.5 : psize; 242 first = false; 243 } else { 244 while (curr.distance(next) >= len) { 245 if (piv) { 246 double rem = len; 247 double s = prev.distance(next); 248 double p = curr.distance(prev); 249 if ((s > 0) && (p > 0)) { 250 double n = curr.distance(next); 251 double theta = Math.acos((s * s + p * p - n * n) / 2 / s / p); 252 double phi = Math.asin(p / len * Math.sin(theta)); 253 rem = len * Math.sin(Math.PI - theta - phi) / Math.sin(theta); 254 } 255 succ = new Point2D.Double(prev.getX() + (rem * Math.cos(angle)), prev.getY() + (rem * Math.sin(angle))); 256 piv = false; 257 } else { 258 succ = new Point2D.Double(curr.getX() + (len * Math.cos(angle)), curr.getY() + (len * Math.sin(angle))); 259 } 260 if (!gap) { 261 Symbols.drawSymbol(g2, symbol, sScale, curr.getX(), curr.getY(), new Scheme(col), 262 new Delta(Handle.BC, AffineTransform.getRotateInstance(Math.atan2((succ.getY() - curr.getY()), (succ.getX() - curr.getX())) + Math.toRadians(90)))); 263 } 264 if (space > 0) 265 gap = !gap; 266 curr = succ; 267 len = gap ? (psize * space) : (--stcount == 0) ? (stflag ? tsize : ssize) : psize; 268 if (stcount == 0) { 269 symbol = stflag ? tersymb : secsymb; 270 if (trect != null) 271 stflag = !stflag; 272 stcount = ratio; 273 } else { 274 symbol = prisymb; 275 } 276 } 277 } 278 } 279 } 280 } 281 } 282 } 283 284 public static void lineVector(LineStyle style) { 285 Path2D.Double p = new Path2D.Double(); 286 p.setWindingRule(GeneralPath.WIND_EVEN_ODD); 287 Point2D point; 288 GeomIterator git = map.new GeomIterator(Rules.feature.geom); 289 while (git.hasComp()) { 290 git.nextComp(); 291 boolean first = true; 292 while (git.hasEdge()) { 293 git.nextEdge(); 294 point = context.getPoint(git.next()); 295 if (first) { 296 p.moveTo(point.getX(), point.getY()); 297 first = false; 298 } else { 299 p.lineTo(point.getX(), point.getY()); 300 } 301 while (git.hasNode()) { 302 Snode node = git.next(); 303 if (node == null) continue; 304 point = context.getPoint(node); 305 p.lineTo(point.getX(), point.getY()); 306 } 307 } 308 } 309 if ((style.fill != null) && (Rules.feature.geom.prim == Pflag.AREA)) { 310 g2.setPaint(style.fill); 311 g2.fill(p); 312 } 313 if (style.line != null) { 314 if (style.dash != null) { 315 float[] dash = new float[style.dash.length]; 316 System.arraycopy(style.dash, 0, dash, 0, style.dash.length); 317 for (int i = 0; i < style.dash.length; i++) { 318 dash[i] *= (float) sScale; 319 } 320 g2.setStroke(new BasicStroke((float) (style.width * sScale), BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 1, dash, 0)); 321 } else { 322 g2.setStroke(new BasicStroke((float) (style.width * sScale), BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); 323 } 324 g2.setPaint(style.line); 325 g2.draw(p); 326 } 327 } 328 329 public static void lineCircle(LineStyle style, double radius, UniHLU units) { 330 switch (units) { 331 case HLU_FEET: 332 radius /= 6076; 333 break; 334 case HLU_KMTR: 335 radius /= 1.852; 336 break; 337 case HLU_HMTR: 338 radius /= 18.52; 339 break; 340 case HLU_SMIL: 341 radius /= 1.15078; 342 break; 343 case HLU_NMIL: 344 break; 345 default: 346 radius /= 1852; 347 break; 348 } 349 radius *= context.mile(Rules.feature); 350 Symbol circle = new Symbol(); 351 if (style.fill != null) { 352 circle.add(new Instr(Form.FILL, style.fill)); 353 circle.add(new Instr(Form.RSHP, new Ellipse2D.Double(-radius, -radius, radius*2, radius*2))); 354 } 355 circle.add(new Instr(Form.FILL, style.line)); 356 circle.add(new Instr(Form.STRK, new BasicStroke(style.width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1, style.dash, 0))); 357 circle.add(new Instr(Form.ELPS, new Ellipse2D.Double(-radius, -radius, radius*2, radius*2))); 358 Point2D point = context.getPoint(Rules.feature.geom.centre); 359 Symbols.drawSymbol(g2, circle, 1, point.getX(), point.getY(), null, null); 360 } 361 362 public static void fillPattern(BufferedImage image) { 363 Path2D.Double p = new Path2D.Double(); 364 p.setWindingRule(GeneralPath.WIND_EVEN_ODD); 365 Point2D point; 366 switch (Rules.feature.geom.prim) { 367 case POINT: 368 point = context.getPoint(Rules.feature.geom.centre); 369 g2.drawImage(image, new AffineTransformOp(AffineTransform.getScaleInstance(sScale, sScale), AffineTransformOp.TYPE_NEAREST_NEIGHBOR), 370 (int) (point.getX() - (50 * sScale)), (int) (point.getY() - (50 * sScale))); 371 break; 372 case AREA: 373 GeomIterator git = map.new GeomIterator(Rules.feature.geom); 374 while (git.hasComp()) { 375 git.nextComp(); 376 boolean newComp = true; 377 while (git.hasEdge()) { 378 git.nextEdge(); 379 point = context.getPoint(git.next()); 380 if (newComp) { 381 p.moveTo(point.getX(), point.getY()); 382 newComp = false; 383 } else { 384 p.lineTo(point.getX(), point.getY()); 385 } 386 while (git.hasNode()) { 387 Snode node = git.next(); 388 if (node == null) continue; 389 point = context.getPoint(node); 390 p.lineTo(point.getX(), point.getY()); 391 } 392 } 393 } 394 g2.setPaint(new TexturePaint(image, new Rectangle(0, 0, 1 + (int) (300 * sScale), 1 + (int) (300 * sScale)))); 395 g2.fill(p); 396 break; 397 default: 398 break; 399 } 400 } 401 402 public static void labelText(String str, Font font, Color tc) { 403 labelText(str, font, tc, LabelStyle.NONE, null, null, null); 404 } 405 406 public static void labelText(String str, Font font, Color tc, Delta delta) { 407 labelText(str, font, tc, LabelStyle.NONE, null, null, delta); 408 } 409 410 public static void labelText(String str, Font font, Color tc, LabelStyle style, Color fg) { 411 labelText(str, font, tc, style, fg, null, null); 412 } 413 414 public static void labelText(String str, Font font, Color tc, LabelStyle style, Color fg, Color bg) { 415 labelText(str, font, tc, style, fg, bg, null); 416 } 417 418 public static void labelText(String str, Font font, Color tc, LabelStyle style, Color fg, Delta delta) { 419 labelText(str, font, tc, style, fg, null, delta); 420 } 421 422 public static void labelText(String str, Font font, Color tc, LabelStyle style, Color fg, Color bg, Delta delta) { 423 if (delta == null) delta = new Delta(Handle.CC); 424 if (bg == null) bg = new Color(0x00000000, true); 425 if ((str == null) || (str.isEmpty())) str = " "; 426 FontRenderContext frc = g2.getFontRenderContext(); 427 GlyphVector gv = font.deriveFont((float) (font.getSize())).createGlyphVector(frc, str.equals(" ") ? "M" : str); 428 Rectangle2D bounds = gv.getVisualBounds(); 429 double width = bounds.getWidth(); 430 double height = bounds.getHeight(); 431 Symbol label = new Symbol(); 432 double lx, ly, tx, ty; 433 switch (style) { 434 case RRCT: 435 width += height * 1.0; 436 height *= 1.5; 437 if (width < height) width = height; 438 lx = -width / 2; 439 ly = -height / 2; 440 tx = lx + (height * 0.34); 441 ty = ly + (height * 0.17); 442 label.add(new Instr(Form.BBOX, new Rectangle2D.Double(lx, ly, width, height))); 443 label.add(new Instr(Form.FILL, bg)); 444 label.add(new Instr(Form.RSHP, new RoundRectangle2D.Double(lx, ly, width, height, height, height))); 445 label.add(new Instr(Form.FILL, fg)); 446 label.add(new Instr(Form.STRK, new BasicStroke(1 + (int) (height/10), BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER))); 447 label.add(new Instr(Form.RRCT, new RoundRectangle2D.Double(lx, ly, width, height, height, height))); 448 break; 449 case VCLR: 450 width += height * 1.0; 451 height *= 2.0; 452 if (width < height) width = height; 453 lx = -width / 2; 454 ly = -height / 2; 455 tx = lx + (height * 0.27); 456 ty = ly + (height * 0.25); 457 label.add(new Instr(Form.BBOX, new Rectangle2D.Double(lx, ly, width, height))); 458 label.add(new Instr(Form.FILL, bg)); 459 label.add(new Instr(Form.RSHP, new RoundRectangle2D.Double(lx, ly, width, height, height, height))); 460 label.add(new Instr(Form.FILL, fg)); 461 int sw = 1 + (int) (height/10); 462 double po = sw / 2; 463 label.add(new Instr(Form.STRK, new BasicStroke(sw, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER))); 464 Path2D.Double p = new Path2D.Double(); p.moveTo(-height*0.2, -ly-po); p.lineTo(height*0.2, -ly-po); p.moveTo(0, -ly-po); p.lineTo(0, -ly-po-(height*0.15)); 465 p.moveTo(-height*0.2, ly+po); p.lineTo((height*0.2), ly+po); p.moveTo(0, ly+po); p.lineTo(0, ly+po+(height*0.15)); 466 label.add(new Instr(Form.PLIN, p)); 467 break; 468 case PCLR: 469 width += height * 1.0; 470 height *= 2.0; 471 if (width < height) width = height; 472 lx = -width / 2; 473 ly = -height / 2; 474 tx = lx + (height * 0.27); 475 ty = ly + (height * 0.25); 476 label.add(new Instr(Form.BBOX, new Rectangle2D.Double(lx, ly, width, height))); 477 label.add(new Instr(Form.FILL, bg)); 478 label.add(new Instr(Form.RSHP, new RoundRectangle2D.Double(lx, ly, width, height, height, height))); 479 label.add(new Instr(Form.FILL, fg)); 480 sw = 1 + (int) (height/10); 481 po = sw / 2; 482 label.add(new Instr(Form.STRK, new BasicStroke(sw, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER))); 483 p = new Path2D.Double(); p.moveTo(-height*0.2, -ly-po); p.lineTo(height*0.2, -ly-po); p.moveTo(0, -ly-po); p.lineTo(0, -ly-po-(height*0.15)); 484 p.moveTo(-height*0.2, ly+po); p.lineTo((height*0.2), ly+po); p.moveTo(0, ly+po); p.lineTo(0, ly+po+(height*0.15)); 485 label.add(new Instr(Form.PLIN, p)); 486 label.add(new Instr(Form.SYMB, new Symbols.SubSymbol(Areas.CableFlash, 1, 0, 0, null, new Delta(Handle.CC, new AffineTransform(0, -1, 1, 0, -width/2, 0))))); 487 label.add(new Instr(Form.SYMB, new Symbols.SubSymbol(Areas.CableFlash, 1, 0, 0, null, new Delta(Handle.CC, new AffineTransform(0, -1, 1, 0, width/2, 0))))); 488 break; 489 case HCLR: 490 width += height * 1.5; 491 height *= 1.5; 492 if (width < height) width = height; 493 lx = -width / 2; 494 ly = -height / 2; 495 tx = lx + (height * 0.5); 496 ty = ly + (height * 0.17); 497 label.add(new Instr(Form.BBOX, new Rectangle2D.Double(lx, ly, width, height))); 498 label.add(new Instr(Form.FILL, bg)); 499 label.add(new Instr(Form.RSHP, new RoundRectangle2D.Double(lx, ly, width, height, height, height))); 500 label.add(new Instr(Form.FILL, fg)); 501 sw = 1 + (int) (height/10); 502 double vo = height / 4; 503 label.add(new Instr(Form.STRK, new BasicStroke(sw, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER))); 504 p = new Path2D.Double(); p.moveTo(-width*0.4-sw, -ly-vo); p.lineTo(-width*0.4-sw, ly+vo); p.moveTo(-width*0.4-sw, 0); p.lineTo(-width*0.4+sw, 0); 505 p.moveTo(width*0.4+sw, -ly-vo); p.lineTo(width*0.4+sw, ly+vo); p.moveTo(width*0.4-sw, 0); p.lineTo(width*0.4+sw, 0); 506 label.add(new Instr(Form.PLIN, p)); 507 break; 508 default: 509 lx = -width / 2; 510 ly = -height / 2; 511 tx = lx; 512 ty = ly; 513 label.add(new Instr(Form.BBOX, new Rectangle2D.Double(lx, ly, width, height))); 514 break; 515 } 516 label.add(new Instr(Form.TEXT, new Caption(str, font, tc, new Delta(Handle.TL, AffineTransform.getTranslateInstance(tx, ty))))); 517 Point2D point = context.getPoint(Rules.feature.geom.centre); 518 Symbols.drawSymbol(g2, label, sScale, point.getX(), point.getY(), null, delta); 519 } 520 521 public static void lineText(String str, Font font, Color colour, double dy) { 522 if (!str.isEmpty()) { 523 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 524 g2.setPaint(colour); 525 FontRenderContext frc = g2.getFontRenderContext(); 526 GlyphVector gv = font.deriveFont(font.getSize2D() * (float) sScale).createGlyphVector(frc, str); 527 double width = gv.getVisualBounds().getWidth(); 528 double height = gv.getVisualBounds().getHeight(); 529 double offset = (Rules.feature.geom.length * context.mile(Rules.feature) - width) / 2; 530 if (offset > 0) { 531 Point2D before = null; 532 Point2D after = null; 533 ArrayList<Point2D> between = new ArrayList<>(); 534 Point2D prev = null; 535 Point2D next = null; 536 double length = 0; 537 double lb = 0; 538 double la = 0; 539 GeomIterator git = map.new GeomIterator(Rules.feature.geom); 540 if (git.hasComp()) { 541 git.nextComp(); 542 while (git.hasEdge()) { 543 git.nextEdge(); 544 while (git.hasNode()) { 545 Snode node = git.next(); 546 if (node == null) 547 continue; 548 prev = next; 549 next = context.getPoint(node); 550 if (prev != null) 551 length += Math.sqrt(Math.pow((next.getX() - prev.getX()), 2) + Math.pow((next.getY() - prev.getY()), 2)); 552 if (length < offset) { 553 before = next; 554 lb = la = length; 555 } else if (after == null) { 556 if (length > (offset + width)) { 557 after = next; 558 la = length; 559 break; 560 } else { 561 between.add(next); 562 } 563 } 564 } 565 if (after != null) 566 break; 567 } 568 } 569 if (after != null) { 570 double angle = Math.atan2((after.getY() - before.getY()), (after.getX() - before.getX())); 571 double rotate = Math.abs(angle) < (Math.PI / 2) ? angle : angle + Math.PI; 572 Point2D mid = new Point2D.Double((before.getX() + after.getX()) / 2, (before.getY() + after.getY()) / 2); 573 Point2D centre = context.getPoint(Rules.feature.geom.centre); 574 AffineTransform pos = AffineTransform.getTranslateInstance(-dy * Math.sin(rotate), dy * Math.cos(rotate)); 575 pos.rotate(rotate); 576 pos.translate((mid.getX() - centre.getX()), (mid.getY() - centre.getY())); 577 Symbol label = new Symbol(); 578 label.add(new Instr(Form.BBOX, new Rectangle2D.Double((-width / 2), (-height), width, height))); 579 label.add(new Instr(Form.TEXT, new Caption(str, font, colour, new Delta(Handle.BC)))); 580 Symbols.drawSymbol(g2, label, sScale, centre.getX(), centre.getY(), null, new Delta(Handle.BC, pos)); 581 } 582 } 583 } 584 } 585 586 public static void lightSector(Color col1, Color col2, double radius, double s1, double s2, Double dir, String str) { 587 if ((zoom >= 16) && (radius > 0.2)) { 588 radius /= (Math.pow(2, zoom-15)); 589 } 590 double mid = (((s1 + s2) / 2) + (s1 > s2 ? 180 : 0)) % 360; 591 g2.setStroke(new BasicStroke((float) (3.0 * sScale), BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 1, new float[] {20 * (float) sScale, 20 * (float) sScale}, 0)); 592 g2.setPaint(Color.black); 593 Point2D.Double centre = (Point2D.Double) context.getPoint(Rules.feature.geom.centre); 594 double radial = radius * context.mile(Rules.feature); 595 if (dir != null) { 596 g2.draw(new Line2D.Double(centre.x, centre.y, centre.x - radial * Math.sin(Math.toRadians(dir)), centre.y + radial * Math.cos(Math.toRadians(dir)))); 597 } else { 598 if ((s1 != 0.0) || (s2 != 360.0)) { 599 g2.draw(new Line2D.Double(centre.x, centre.y, centre.x - radial * Math.sin(Math.toRadians(s1)), centre.y + radial * Math.cos(Math.toRadians(s1)))); 600 g2.draw(new Line2D.Double(centre.x, centre.y, centre.x - radial * Math.sin(Math.toRadians(s2)), centre.y + radial * Math.cos(Math.toRadians(s2)))); 601 } 602 } 603 double arcWidth = 10.0 * sScale; 604 g2.setStroke(new BasicStroke((float) arcWidth, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1)); 605 g2.setPaint(col1); 606 g2.draw(new Arc2D.Double(centre.x - radial, centre.y - radial, 2 * radial, 2 * radial, -(s1 + 90), ((s1 < s2) ? (s1 - s2) : (s1 - s2 - 360)), Arc2D.OPEN)); 607 if (col2 != null) { 608 g2.setPaint(col2); 609 g2.draw(new Arc2D.Double(centre.x - radial + arcWidth, centre.y - radial + arcWidth, 2 * (radial - arcWidth), 2 * (radial - arcWidth), -(s1 + 90), ((s1 < s2) ? (s1 - s2) : (s1 - s2 - 360)), Arc2D.OPEN)); 610 } 611 if ((str != null) && (!str.isEmpty())) { 612 Font font = new Font("Arial", Font.PLAIN, 40); 613 double arc = (s2 > s1) ? (s2 - s1) : (s2 - s1 + 360); 614 double awidth = (Math.toRadians(arc) * radial); 615 boolean hand = ((mid > 270) || (mid < 90)); 616 double phi = Math.toRadians(mid); 617 radial += 30 * sScale; 618 AffineTransform at = AffineTransform.getTranslateInstance(-radial * Math.sin(phi) / sScale, radial * Math.cos(phi) / sScale); 619 if ((font.getSize() * sScale * str.length()) < awidth) { 620 at.rotate(Math.toRadians(mid + (hand ? 0 : 180))); 621 labelText(str, font, Color.black, new Delta(Handle.CC, at)); 622 } else if ((font.getSize() * sScale) < awidth) { 623 hand = (mid < 180); 624 at.rotate(Math.toRadians(mid + (hand ? -90 : 90))); 625 labelText(str, font, Color.black, hand ? new Delta(Handle.RC, at) : new Delta(Handle.LC, at)); 626 } 627 if (dir != null) { 628 font = new Font("Arial", Font.PLAIN, 30); 629 str = dir + "°"; 630 hand = (dir > 180); 631 phi = Math.toRadians(dir + (hand ? -0.5 : 0.5)); 632 radial -= 70 * sScale; 633 at = AffineTransform.getTranslateInstance(-radial * Math.sin(phi) / sScale, radial * Math.cos(phi) / sScale); 634 at.rotate(Math.toRadians(dir + (hand ? 90 : -90))); 635 labelText(str, font, Color.black, hand ? new Delta(Handle.BR, at) : new Delta(Handle.BL, at)); 636 } 637 } 638 } 605 639 }
Note:
See TracChangeset
for help on using the changeset viewer.
