[vassalengine-svn] SF.net SVN: vassalengine:[9195] VSQL-src/trunk
Brought to you by:
rodneykinney,
uckelman
From: <swa...@us...> - 2015-05-21 07:03:50
|
Revision: 9195 http://sourceforge.net/p/vassalengine/svn/9195 Author: swampwallaby Date: 2015-05-21 07:03:47 +0000 (Thu, 21 May 2015) Log Message: ----------- Full LOS checking working. Modified Paths: -------------- VSQL-src/trunk/tdc/AttackWizard.java VSQL-src/trunk/tdc/BlockingTerrain.java VSQL-src/trunk/tdc/BlockingTerrainMap.java VSQL-src/trunk/tdc/EdgeBlockingTerrain.java VSQL-src/trunk/tdc/HexBlockingTerrain.java VSQL-src/trunk/tdc/TdcMap.java VSQL-src/trunk/tdc/WizardThread.java VSQL-src/trunk/terrain/TerrainEdge.java VSQL-src/trunk/terrain/TerrainHexGrid.java VSQL-src/trunk/terrain/TerrainMap.java Added Paths: ----------- VSQL-src/trunk/tdc/AttrBlockingTerrain.java VSQL-src/trunk/tdc/Gradient.java VSQL-src/trunk/tdc/LOS.java Modified: VSQL-src/trunk/tdc/AttackWizard.java =================================================================== --- VSQL-src/trunk/tdc/AttackWizard.java 2015-05-18 03:46:31 UTC (rev 9194) +++ VSQL-src/trunk/tdc/AttackWizard.java 2015-05-21 07:03:47 UTC (rev 9195) @@ -46,7 +46,6 @@ import tdc.attack.AttackView; import tdc.attack.FireModifier; import tdc.attack.FireResolver; -import tdc.attack.AttackModel.BeachAttackUnitInfo; import VASSAL.build.AbstractConfigurable; import VASSAL.build.Buildable; import VASSAL.build.GameModule; @@ -262,7 +261,7 @@ source = piece; sourceInfo = new UnitInfo(piece, true); isAirDefence = false; - targetSelected(source.getPosition(), 0); + targetSelected(source.getPosition(), 0, null); } public void launchAirDefenceAttack(GamePiece piece) { @@ -303,7 +302,7 @@ * selects a target stack */ - public void targetSelected(Point p, int rangeToTarget) { + public void targetSelected(Point p, int rangeToTarget, WizardThread losThread) { if (SHOW_WIZARD) { setTarget(p, rangeToTarget); @@ -311,6 +310,9 @@ final Command wizCmd = new WizardOpenCommand(this, source.getId(), targetPoint, rangeToTarget); final Command reportCmd = getChatCommand("START ATTACK", true); reportCmd.append(getChatCommand(myModel.getAttackText() + " - " + myModel.getSmlModeString(), false)); + if (losThread.isBlocked()) { + reportCmd.append(getChatCommand("*** LOS May be blocked by terrain: "+losThread.getBlockingReasons()+" ***", false)); + } reportCmd.execute(); wizCmd.append(reportCmd); GameModule.getGameModule().sendAndLog(wizCmd); Added: VSQL-src/trunk/tdc/AttrBlockingTerrain.java =================================================================== --- VSQL-src/trunk/tdc/AttrBlockingTerrain.java (rev 0) +++ VSQL-src/trunk/tdc/AttrBlockingTerrain.java 2015-05-21 07:03:47 UTC (rev 9195) @@ -0,0 +1,47 @@ +/* + * $Id: AttrBlockingTerrain.java 9192 2015-05-16 01:24:32Z swampwallaby $ + * + * Copyright (c) 2015 by Brent Easton + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License (LGPL) as published by the Free Software Foundation. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, copies are available + * at http://www.opensource.org. + */ + +package tdc; + +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.geom.Point2D; + +import terrain.AttributeTerrain; +import terrain.TerrainAttribute; + +public class AttrBlockingTerrain extends HexBlockingTerrain { + + protected TerrainAttribute attr; + + public AttrBlockingTerrain(TdcMap map, TerrainAttribute attr, Rectangle offset) { + super(map, attr.getTerrain().getTerrainName(), offset); + this.attr = attr; + setCenter(offset (attr.getLocation().getCenter(), offset)); + final AttributeTerrain ter = attr.getTerrain(); + setPossiblyBlocking (ter.isPossibleBlocking()); + } + + protected void calculateBaseShape() { + final Point2D.Float p = attr.getLocation().getCenter(); + shape = attr.getLocation().getGrid().getSingleHex(new Point (Math.round(p.x), Math.round(p.y))); + transformBaseShape(); + } + +} Property changes on: VSQL-src/trunk/tdc/AttrBlockingTerrain.java ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Modified: VSQL-src/trunk/tdc/BlockingTerrain.java =================================================================== --- VSQL-src/trunk/tdc/BlockingTerrain.java 2015-05-18 03:46:31 UTC (rev 9194) +++ VSQL-src/trunk/tdc/BlockingTerrain.java 2015-05-21 07:03:47 UTC (rev 9195) @@ -23,22 +23,33 @@ import java.awt.Point; import java.awt.Rectangle; import java.awt.geom.Point2D; +import java.util.HashSet; +import java.util.Iterator; public abstract class BlockingTerrain { protected Point2D.Float center; - protected String description; protected TdcMap map; protected boolean possiblyBlocking; + protected HashSet<String> reasons = new HashSet<String>(); public BlockingTerrain(TdcMap map, String description) { this.map = map; - this.description = description; + addReason(description); } public void setCenter(Point2D.Float p) { center = new Point2D.Float(p.x, p.y); } + public void setCenter(Point p) { + center = new Point2D.Float(p.x, p.y); + } + + // Is this the center of the hex (allow for rounding) + public boolean hasCenter (Point p) { + return Math.abs(p.x-center.x) < 5 && Math.abs(p.y-center.y) < 5; + } + public float getX() { return center.x; } @@ -51,10 +62,6 @@ return center; } - public String getDescription() { - return description; - } - public boolean isPossiblyBlocking() { return possiblyBlocking; } @@ -63,14 +70,10 @@ possiblyBlocking = b; } - public abstract void draw(Graphics g); + public abstract void draw(Graphics g, WizardThread thread); - public abstract boolean intersects(Point2D.Float p1, Point2D.Float p2); + public abstract boolean intersects(LOS los); - public boolean intersects(Point p1, Point p2) { - return intersects (new Point2D.Float(p1.x, p1.y), new Point2D.Float(p2.x, p2.y)); - } - protected Point offset(Point p, Rectangle offset) { return new Point(p.x + offset.x, p.y + offset.y); } @@ -78,4 +81,12 @@ protected Point2D.Float offset(Point2D.Float p, Rectangle offset) { return new Point2D.Float(p.x + offset.x, p.y + offset.y); } + + public void addReason(String r) { + if (! reasons.contains(r)) reasons.add(r); + } + + public Iterator<String> getReasons() { + return reasons.iterator(); + } } \ No newline at end of file Modified: VSQL-src/trunk/tdc/BlockingTerrainMap.java =================================================================== --- VSQL-src/trunk/tdc/BlockingTerrainMap.java 2015-05-18 03:46:31 UTC (rev 9194) +++ VSQL-src/trunk/tdc/BlockingTerrainMap.java 2015-05-21 07:03:47 UTC (rev 9195) @@ -24,10 +24,9 @@ import java.awt.Point; import java.awt.Rectangle; -import java.awt.geom.Point2D; -import java.util.ArrayList; +import java.util.HashSet; import java.util.Iterator; -import java.util.List; +import java.util.Set; import qtree.QPoint; import qtree.QuadTree; @@ -85,19 +84,19 @@ } - protected void processTerrainMap(Board board, TerrainMap tmap) { + protected void processTerrainMap(Board board, TerrainMap tmap) { if (tmap == null) { return; } - + Rectangle bounds = board.bounds(); - + // Process Edges for (Iterator<TerrainEdge> i = tmap.getAllEdgeTerrain(); i.hasNext();) { - final TerrainEdge edge = i.next(); + final TerrainEdge edge = i.next(); final EdgeTerrain ter = edge.getTerrain(); if (ter.isBlocking()) { - final BlockingTerrain block = new EdgeBlockingTerrain (map, edge, bounds); + final BlockingTerrain block = new EdgeBlockingTerrain(map, edge, bounds); try { terrain.set(block.getX(), block.getY(), block); } @@ -106,12 +105,12 @@ } } } - + // Process Hexes for (TerrainHex hex : tmap.getAllHexTerrain()) { final HexTerrain ter = hex.getTerrain(); if (ter.isBlocking() || ter.isPossibleBlocking()) { - final BlockingTerrain block = new HexBlockingTerrain (map, hex, bounds); + final BlockingTerrain block = new HexBlockingTerrain(map, hex, bounds); try { terrain.set(block.getX(), block.getY(), block); } @@ -120,14 +119,40 @@ } } } - + // And Tags for (Iterator<TerrainAttribute> i = tmap.getAllAttributeTerrain(); i.hasNext();) { final TerrainAttribute attribute = i.next(); final AttributeTerrain ter = attribute.getTerrain(); if (ter.isBlocking() || ter.isPossibleBlocking()) { + final BlockingTerrain abt = new AttrBlockingTerrain(map, attribute, bounds); + BlockingTerrain existing = (BlockingTerrain) terrain.get(abt.getX(), abt.getY(), null); + + // This Hex not recorded yet, + if (existing == null) { + existing = abt; + } + // Hex is already blocked, ignore this attribute + else if (!existing.isPossiblyBlocking()) { + existing.addReason(attribute.getName()); + continue; + } + // hex is already Possibly blocked and attribute is possibly blocked, + // ignore + else if (existing.isPossiblyBlocking() && abt.isPossiblyBlocking()) { + existing.addReason(attribute.getName()); + continue; + } + // Hex is only possibly blocked, but attribute is Blocking, upgrade + // existing to blocked. + else { + existing.addReason(attribute.getName()); + existing.setPossiblyBlocking(false); + } + + // Set the new or updated block. try { - ; + terrain.set(existing.getX(), existing.getY(), existing); } catch (QuadTreeException e) { ; // Centre point of Hex outside map bounds. @@ -135,34 +160,284 @@ } } } - - // Find all blocking terrain that intersects with the LOS from start to end - public void findBlockingTerrain (Point start, Point end, List<BlockingTerrain> blockingTerrain) { + /* + * Find all blocking terrain that intersects with the LOS from start to end + */ + public void findBlockingTerrain(Point start, Point end, Set<BlockingTerrain> blockingTerrain) { + if (blockingTerrain == null) { - blockingTerrain = new ArrayList<BlockingTerrain>(); + blockingTerrain = new HashSet<BlockingTerrain>(); } else { blockingTerrain.clear(); } - - // Search for all terrain with the bounding box defining the LOS. Add a 50 pixel fudge to pick up + + // If the LOS runs along Hex edges, then the standard intersection testing + // fails. + final LOS los = new LOS(map, start, end); + + // Search for all terrain with the bounding box defining the LOS. Add a 50 + // pixel fudge to pick up // hexes and edges whose center maybe just outside the bounding box. - - final int minX = Math.min(start.x, end.x) - 50; - final int minY = Math.min(start.y, end.y) - 50; - final int maxX = Math.max(start.x, end.x) + 50; - final int maxY = Math.max(start.y, end.y) + 50; - + // Return any blocking terrain that intersects with the LOS. + + final int minX = Math.min(start.x, end.x) - 50; + final int minY = Math.min(start.y, end.y) - 50; + final int maxX = Math.max(start.x, end.x) + 50; + final int maxY = Math.max(start.y, end.y) + 50; + final QPoint[] results = terrain.searchIntersect(minX, minY, maxX, maxY); - + for (QPoint qp : results) { - final BlockingTerrain bt = (BlockingTerrain) qp.getValue(); - if (bt.intersects(start, end)) { + final BlockingTerrain bt = (BlockingTerrain) qp.getValue(); + if (!bt.hasCenter(start)) { + if (bt.intersects(los)) { blockingTerrain.add(bt); } + } } - } - + +// /* +// * The intersection method of finding blocking terrain fails miserably when +// * the LOS runs exactly along hex sides. A random mixture of fake positives +// * and fake negatives results Instead, use this algorithm: +// * +// * 1. Step along the LOS from start to finish in x pixel (unzoomed Map +// * co-ordinate) steps. This will ensure we touch every hex along the LOS. Each +// * point will either be within a hex or on an Edge +// * +// * 2. If the point is within a Hex, then just check terrain and add if +// * blocking +// * +// * 3. If the point is on an edge then 3.1 Check the Edge and include it if it +// * is blocking. 3.2 Identify the 2 hexes on either side of the edge and check +// * them for blocking. - Neither blocking, do not add either - 1 is blocking, +// * other is not, do not add either - both are full blocking, add both - both +// * are possible blocking or 1 is full and 1 is possible, then add both as +// * possible. 3.3 For each side hex, identify the 2 edges that run off the LOS +// * and add them if blocking. +// */ +// public void searchAlongLOS(LOS los, Set<BlockingTerrain> blockingTerrain) { +// +// final HashSet<Point> checked = new HashSet<Point>(); +// +// final Board board = map.findBoard(los.getStart()); +// final Rectangle bounds = board.bounds(); +// +// final int startCheck = 100; // No point in starting search until outside the +// // starting hex +// final int step = 40; +// +// final int xLen = los.getEnd().x - los.getStart().x; +// final int yLen = los.getEnd().y - los.getStart().y; +// +// final int length = (int) Math.sqrt(xLen * xLen + yLen * yLen); +// +// for (int i = startCheck; i < length; i += step) { +// final int x = los.getStart().x + i * xLen / length; +// final int y = los.getStart().y + i * yLen / length; +// final Point p = new Point(x, y); +// +// final TerrainHexGrid grid = map.findTerrainHexGrid(p); +// +// // Snap point to nearest hex center +// Point snap = snapToHex(p, grid, bounds); +// +// // Is this hex on the LOS and has not been checked before +// +// if (!checked.contains(snap)) { +// +// if (los.isOnLine(snap)) { +// // It's a new Hex right on the LOS. If is is blocking terrain, add it +// // in. +// final BlockingTerrain bt = findTerrain(snap); +// if (bt != null) { +// if (!blockingTerrain.contains(bt)) +// blockingTerrain.add(bt); +// } +// } +// } +// checked.add(new Point(snap)); +// +// // Now snap the same point to the nearest Hex edge +// snap = snapToEdge(p, grid, bounds); +// +// // Is this Edge on the LOS and has not been checked before? +// if (!checked.contains(snap)) { +// if (los.isOnLine(snap)) { +// // It's a new Edge right on the LOS. If is blocking terrain, add it +// // in. +// final BlockingTerrain bt = findTerrain(snap); +// if (bt != null) { +// if (!blockingTerrain.contains(bt)) +// blockingTerrain.add(bt); +// } +// +// // Next need to check the hex on either side of the edge to see if +// // both +// // are blocking. +// Point h1 = snapToHex(new Point(snap.x - 20, snap.y - 20), grid, bounds); +// HexBlockingTerrain t1 = (HexBlockingTerrain) findTerrain(h1); +// +// Point h2 = snapToHex(new Point(snap.x + 20, snap.y + 20), grid, bounds); +// HexBlockingTerrain t2 = (HexBlockingTerrain) findTerrain(h2); +// +// // If either is not blocking, then there is no block to LOS +// // If either is possibly blocking, then record both as possibles. +// // If both are full blocking +// if (t1 != null && t2 != null) { +// if (t1.isPossiblyBlocking() || t2.isPossiblyBlocking()) { +// if (!t1.isPossiblyBlocking()) +// t1 = new HexBlockingTerrain((HexBlockingTerrain) t1, true); +// if (!t2.isPossiblyBlocking()) +// t2 = new HexBlockingTerrain((HexBlockingTerrain) t2, true); +// } +// if (!blockingTerrain.contains(t1)) +// blockingTerrain.add(t1); +// if (!blockingTerrain.contains(t2)) +// blockingTerrain.add(t2); +// } +// +// // Finally, check the edges of the straddling edges that touch the LOS +// // and add them +// BlockingTerrain e1 = null; +// BlockingTerrain e2 = null; +// findIntersectingEdges(los, h1, e1, e2, grid, bounds); +// findIntersectingEdges(los, h2, e1, e2, grid, bounds); +// +// if (e1 != null && ! blockingTerrain.contains(e1)) blockingTerrain.add(e1); +// if (e2 != null && ! blockingTerrain.contains(e2)) blockingTerrain.add(e2); +// +// } +// +// // Record this snap point as already been checked +// checked.add(new Point(snap)); +// +// } +// } +// } +// +// /** +// * The Line from P1 to P2 runs along one of the Edges of the Hex whose center +// * is center. Find the two edges of the Hex that intersect p1/p2 and return +// * their terrain if blocking +// * +// * @param los +// * The current LOS +// * @param center +// * Centre of Hex in Map coords +// * @param e1 +// * Edge blocking terrain of 1st intersecting Edge +// * @param e2 +// * Edge blocking terrain of 2nd intersecting Edge +// * @Param grid TerrainHexGrid of board containing hex +// * @oaram bounds Bounds of Board containing hex +// */ +// protected void findIntersectingEdges(LOS los, Point center, BlockingTerrain e1, BlockingTerrain e2, TerrainHexGrid grid, Rectangle bounds) { +// +// e1 = null; +// e2 = null; +// +// final Point hexCenter = toBoardCoords(center, bounds); +// final Point[] v = grid.getHexVertices(hexCenter.x, hexCenter.y); +// +// // Find the 2 intersecting edges +// int v1 = -1; +// int v2 = -1; +// for (int i = 0; i < v.length; i++) { +// v[i] = toMapCoords(v[i], bounds); +// if (los.isOnLine(v[i])) { +// System.out.println("Vertex " + i + " is on LOS"); +// if (v1 < 0) { +// v1 = i; +// } +// else { +// v2 = i; +// } +// } +// } +// +// if (v1 < 0 || v2 < 0) return; +// +// int w1s = 0, w1e = 0, w2s = 0, w2e = 0; +// +// +// if (v1 == 0) { +// if (v2 == 1) { +// w1s = 0; +// w1e = 5; +// w2s = 1; +// w2e = 2; +// } +// else { +// w1s = 0; +// w1e = 1; +// w2s = 4; +// w2e = 5; +// } +// } +// else if (v1==4) { +// w1s = 3; +// w1e = 4; +// w2s = 0; +// w2e = 5; +// } +// else { +// w1s = v1 - 1; +// w1e = v1; +// w2s = v2; +// w2e = v2 + 1; +// } +// +// Point e1p1 = v[w1s]; +// Point e1p2 = v[w1e]; +// Point e2p1 = v[w2s]; +// Point e2p2 = v[w2e]; +// +// Point e1c = toBoardCoords(new Point (e1p1.x + (int) ((e1p2.x-e1p1.x)/2), e1p1.y + (int) ((e1p2.y-e1p1.y)/2)), bounds); +// Point e2c = toBoardCoords(new Point (e2p1.x + (int) ((e2p2.x-e2p1.x)/2), e2p1.y + (int) ((e2p2.y-e2p1.y)/2)), bounds); +// +// Point e1cs = toMapCoords(grid.snapToHexSide(e1c), bounds); +// Point e2cs = toMapCoords(grid.snapToHexSide(e2c), bounds); +// +// e1 = findTerrain(e1cs); +// e2 = findTerrain(e2cs); +// +// +// } +// +// protected Point toBoardCoords(Point p, Rectangle offset) { +// return new Point(p.x - offset.x, p.y - offset.y); +// } +// +// protected Point toMapCoords(Point p, Rectangle offset) { +// return new Point(p.x + offset.x, p.y + offset.y); +// } +// +// protected Point snapToHex(Point p, TerrainHexGrid grid, Rectangle bounds) { +// Point snap = new Point(p); +// snap.translate(-bounds.x, -bounds.y); +// snap = grid.snapToHex(snap); +// snap.translate(bounds.x, bounds.y); +// return snap; +// } +// +// protected Point snapToEdge(Point p, TerrainHexGrid grid, Rectangle bounds) { +// Point snap = new Point(p); +// snap.translate(-bounds.x, -bounds.y); +// snap = grid.snapToHexSide(snap); +// snap.translate(bounds.x, bounds.y); +// return snap; +// } +// +// protected BlockingTerrain findTerrain(Point p) { +// +// final QPoint[] results = terrain.searchIntersect(p.x - 5, p.y - 5, p.x + 5, p.y + 5); +// if (results.length == 0) { +// return null; +// } +// return (BlockingTerrain) results[0].getValue(); +// } } \ No newline at end of file Modified: VSQL-src/trunk/tdc/EdgeBlockingTerrain.java =================================================================== --- VSQL-src/trunk/tdc/EdgeBlockingTerrain.java 2015-05-18 03:46:31 UTC (rev 9194) +++ VSQL-src/trunk/tdc/EdgeBlockingTerrain.java 2015-05-21 07:03:47 UTC (rev 9195) @@ -21,47 +21,44 @@ package tdc; import java.awt.BasicStroke; -import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; -import java.awt.Point; import java.awt.Rectangle; import java.awt.Stroke; +import java.awt.geom.Area; +import java.awt.geom.GeneralPath; import java.awt.geom.Line2D; import java.awt.geom.Point2D; -import java.awt.geom.Point2D.Float; import terrain.TerrainEdge; public class EdgeBlockingTerrain extends BlockingTerrain { - public static final float MAX_GRADIENT = 1000; - Point2D.Float end1; - Point2D.Float end2; - double gradient; + protected Point2D.Float end1; + protected Point2D.Float end2; + protected Gradient gradient; + protected Area fatShape; + protected String terrainName; + public EdgeBlockingTerrain (TdcMap map, TerrainEdge edge, Rectangle offset) { super(map, edge.getTerrain().getTerrainName()); setCenter(offset (edge.getCenter(), offset)); end1 = offset (edge.getEnd1(), offset); end2 = offset (edge.getEnd2(), offset); - gradient = calculateGradient(end1, end2); - System.out.println ("Edge Gradient="+gradient); - if (Math.abs(gradient) > 0.1f && Math.abs(gradient) < 1.7f) { - System.out.println (edge.getTerrain().getTerrainName()); - System.out.println ("Row="+edge.getReference().getRow()+", Col="+edge.getReference().getColumn()); - } + gradient = new Gradient(end1, end2); + terrainName = edge.getTerrain().getTerrainName(); } - public void draw (Graphics g) { + public void draw (Graphics g, WizardThread thread) { final Point2D.Float p1 = map.componentCoordinates2D(end1); final Point2D.Float p2 = map.componentCoordinates2D(end2); final Graphics2D g2 = (Graphics2D) g; - if (description.equals(TdcProperties.RIDGE)) { - g2.setColor(Color.ORANGE); + if (terrainName.equals(TdcProperties.RIDGE)) { + g2.setColor(thread.getRidgeColor()); } else { - g2.setColor(Color.YELLOW); + g2.setColor(thread.getCrestColor()); } final Stroke saveStroke = g2.getStroke(); @@ -83,9 +80,8 @@ // the same (almost) and centre if the edge segment will be on the LOS (almost) if (! intersects) { - final double losGradient = calculateGradient (p1, p2); - // System.out.println("Gradient diff is "+(losGradient-gradient)+"los="+losGradient+", Edge="+gradient); - if (Math.abs(losGradient - gradient) < 1) { + final Gradient losGradient = new Gradient (p1, p2); + if (losGradient.equals(gradient)) { } } @@ -93,19 +89,37 @@ return intersects; } - - protected float calculateGradient (Point2D.Float p1, Point2D.Float p2) { - float g; - - try { - g = (p2.y - p1.y) / (p2.x - p1.x); - } - catch (Exception x) { - g = MAX_GRADIENT; - } - - if ( g > MAX_GRADIENT) g = MAX_GRADIENT; - - return g; - } + /* + * Does the supplied LOS intersect this Edge? + * If the LOS is non-spinal, just check for intersection of the Line segments. + * For a spinal LOS (running along hex edges), create a fatter Area that includes the Edge + * and check for intersection with that. + */ + public boolean intersects(LOS los) { + + boolean intersects = false; + + if (los.isSpinal()) { + intersects = los.intersects(getFatShape()); + } + else { + intersects = los.intersects(end1.x, end1.y, end2.x, end2.y); + } + + return intersects; + } + + public Area getFatShape() { + float offset = 5f; + if (fatShape == null) { + GeneralPath path = new GeneralPath(); + path.moveTo(end1.x, end1.y-offset); + path.lineTo(end2.x, end2.y-offset); + path.lineTo(end2.x, end2.y+offset); + path.lineTo(end1.x, end1.y+offset); + path.closePath(); + fatShape = new Area(path); + } + return fatShape; + } } \ No newline at end of file Added: VSQL-src/trunk/tdc/Gradient.java =================================================================== --- VSQL-src/trunk/tdc/Gradient.java (rev 0) +++ VSQL-src/trunk/tdc/Gradient.java 2015-05-21 07:03:47 UTC (rev 9195) @@ -0,0 +1,71 @@ +/* + * $Id: gradient.java 9192 2015-05-16 01:24:32Z swampwallaby $ + * + * Copyright (c) 2015 by Brent Easton + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License (LGPL) as published by the Free Software Foundation. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, copies are available + * at http://www.opensource.org. + */ + +package tdc; + +import java.awt.Point; +import java.awt.geom.Point2D; + +/** + * The Gradient of a Line + * @author Brent + * + */ +public class Gradient { + + // Any gradient > 1000 (including +/- infinity) is stored as 1000 + public static final float MAX_GRADIENT = 1000; + + // Two gradients are the same if within this value + public static final float FUDGE_GRADIENT = 0.005f; + + protected float gradient; + + public Gradient (Point p1, Point p2) { + this (new Point2D.Float(p1.x, p1.y), new Point2D.Float(p2.x, p2.y)); + } + + public Gradient (Point2D.Float p1, Point2D.Float p2) { + + try { + gradient = (p2.y - p1.y) / (p2.x - p1.x); + } + catch (Exception x) { + gradient = MAX_GRADIENT; + } + + if (gradient > MAX_GRADIENT || gradient < -MAX_GRADIENT) gradient = MAX_GRADIENT; + + } + + public float getGradient () { + return gradient; + } + + public boolean equals (Gradient g) { + return equals(g.getGradient()); + } + + public boolean equals(float g) { + float d = Math.abs(g - getGradient()); + return d <= FUDGE_GRADIENT ; + } + +} + \ No newline at end of file Property changes on: VSQL-src/trunk/tdc/Gradient.java ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Modified: VSQL-src/trunk/tdc/HexBlockingTerrain.java =================================================================== --- VSQL-src/trunk/tdc/HexBlockingTerrain.java 2015-05-18 03:46:31 UTC (rev 9194) +++ VSQL-src/trunk/tdc/HexBlockingTerrain.java 2015-05-21 07:03:47 UTC (rev 9195) @@ -19,8 +19,9 @@ package tdc; +import java.awt.AlphaComposite; import java.awt.BasicStroke; -import java.awt.Color; +import java.awt.Composite; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; @@ -28,89 +29,138 @@ import java.awt.Stroke; import java.awt.geom.AffineTransform; import java.awt.geom.Area; -import java.awt.geom.GeneralPath; -import java.awt.geom.Point2D; import terrain.HexTerrain; import terrain.TerrainHex; - public class HexBlockingTerrain extends BlockingTerrain { - - protected Area shape; - protected double lastZoom = 0; - protected TerrainHex hex; - protected Rectangle boardOffset; - GeneralPath path; +public class HexBlockingTerrain extends BlockingTerrain { - public HexBlockingTerrain(TdcMap map, TerrainHex hex, Rectangle offset) { - super (map, hex.getTerrain().getTerrainName()); - setCenter(offset (hex.getLocation().getCenter(), offset)); - final HexTerrain ter = hex.getTerrain(); - setPossiblyBlocking (ter.isPossibleBlocking()); - this.hex = hex; - this.boardOffset = offset; - } - - public void draw (Graphics g) { - // final Point p = map.componentCoordinates2D(getCenter()); - final Graphics2D g2 = (Graphics2D) g; - - final Stroke saveStroke = g2.getStroke(); - final Shape saveClip = g2.getClip(); - g2.setClip(getShape()); - g2.setColor(Color.RED); - g2.setStroke(new BasicStroke((float) (12.0f * map.getZoom()), BasicStroke.CAP_ROUND, - BasicStroke.JOIN_ROUND)); - g2.draw(getShape()); - g2.setStroke(saveStroke); - g2.setClip(saveClip); - - if (path != null) { - g2.draw(path); + protected Area shape; // The displayable shape of this Hex after zooming + // (Zoomed Map-coords) + protected Area mapShape; // The unzoomed shape of the Hex (Zoom = 1 Map + // co-ords) + protected Area fatShape; // An oversized version of mapShape for testing + // intersection with spinal LOS + + protected double lastZoom = 0; + protected TerrainHex hex; + protected Rectangle boardOffset; + + public HexBlockingTerrain(TdcMap map, String terrainName, Rectangle offset) { + super(map, terrainName); + this.boardOffset = offset; + } + + public HexBlockingTerrain(TdcMap map, TerrainHex hex, Rectangle offset) { + this(map, hex.getTerrain().getTerrainName(), offset); + setCenter(offset(hex.getLocation().getCenter(), offset)); + final HexTerrain ter = hex.getTerrain(); + setPossiblyBlocking(ter.isPossibleBlocking()); + this.hex = hex; + } + + public HexBlockingTerrain(HexBlockingTerrain hbt) { + this(hbt.map, hbt.hex, hbt.boardOffset); + } + + public HexBlockingTerrain(HexBlockingTerrain hbt, boolean possiblyBlocked) { + this(hbt); + setPossiblyBlocking(possiblyBlocked); + } + + // Draw the blocked Hex + public void draw(Graphics g, WizardThread thread) { + + final Graphics2D g2 = (Graphics2D) g; + + final Stroke saveStroke = g2.getStroke(); + final Shape saveClip = g2.getClip(); + final Composite oldComposite = g2.getComposite(); + + g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.6f)); + + g2.setClip(getZoomedShape()); + g2.setColor(isPossiblyBlocking() ? thread.getPossibleColor() : thread.getBlockColor()); + g2.setStroke(new BasicStroke((float) (20.0f * map.getZoom()), BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g2.draw(getZoomedShape()); + g2.setStroke(saveStroke); + g2.setClip(saveClip); + g2.setComposite(oldComposite); + } + + // Get the displayable shape of this Hex. + public Area getZoomedShape() { + if (shape == null || lastZoom != map.getZoom()) { + calculateZoomedShape(); } + return shape; + } + + // Get the unzoomed Shape + public Area getMapShape() { + if (mapShape == null) { + calculateBaseShape(); } - - public Area getShape () { - if (shape == null || lastZoom != map.getZoom()) { - calculateShape(); - } - return shape; + return mapShape; + } + + // Get a larger sized unzoomed shape + public Area getFatShape() { + if (fatShape == null) { + calculateFatShape(); } - - protected void calculateShape() { - shape = hex.getLocation().getGrid().getSingleHex(hex); - final AffineTransform translate = new AffineTransform(); - translate.translate(boardOffset.x, boardOffset.y); - final AffineTransform scale = new AffineTransform(); - scale.scale(map.getZoom(), map.getZoom()); + return fatShape; + } - shape.transform(translate); - shape.transform(scale); - - lastZoom = map.getZoom(); + // Calculate the shape of this Hex + protected void calculateBaseShape() { + + // Get the Shape in Board coords and convert it to Map coords + mapShape = hex.getLocation().getGrid().getSingleHex(hex); + transformBaseShape(); + } + + protected void transformBaseShape() { + final AffineTransform translate = new AffineTransform(); + translate.translate(boardOffset.x, boardOffset.y); + mapShape.transform(translate); + } + + protected void calculateFatShape() { + fatShape = hex.getLocation().getGrid().getSingleFatHex(hex); + final AffineTransform translate = new AffineTransform(); + translate.translate(boardOffset.x, boardOffset.y); + fatShape.transform(translate); + } + + // + // Calculate the Zoomed shape + protected void calculateZoomedShape() { + + if (mapShape == null) { + calculateBaseShape(); } + + shape = new Area(mapShape); + if (map.getZoom() < .999 || map.getZoom() < 1.001) { + final AffineTransform scale = new AffineTransform(); + scale.scale(map.getZoom(), map.getZoom()); + shape.transform(scale); + } + lastZoom = map.getZoom(); + + } + + // Does the Hex intersect with the supplied LOS? + public boolean intersects(LOS los) { - public boolean intersects(Point2D.Float p1, Point2D.Float p2) { - boolean intersects; - - final Point2D.Float p3 = new Point2D.Float(p1.x*(float) map.getZoom(), p1.y*(float)map.getZoom()); - final Point2D.Float p4 = new Point2D.Float(p2.x*(float) map.getZoom(), p2.y*(float)map.getZoom()); - - path = new GeneralPath(); - path.moveTo(p3.x, p3.y); - path.lineTo(p3.x - 0.01f, p3.y - 0.01f); - path.lineTo(p4.x - 0.01f, p4.y - 0.01f); - path.lineTo(p4.x, p4.y); - path.closePath(); - final Area a = new Area(path); - - a.intersect(getShape()); - - - intersects = ! a.isEmpty(); - - return intersects; - + if (los.isSpinal()) { + return los.intersects(getFatShape()); } - - } \ No newline at end of file + else { + return los.intersects(getMapShape()); + } + + } + +} \ No newline at end of file Added: VSQL-src/trunk/tdc/LOS.java =================================================================== --- VSQL-src/trunk/tdc/LOS.java (rev 0) +++ VSQL-src/trunk/tdc/LOS.java 2015-05-21 07:03:47 UTC (rev 9195) @@ -0,0 +1,149 @@ +/* + * $Id: gradient.java 9192 2015-05-16 01:24:32Z swampwallaby $ + * + * Copyright (c) 2015 by Brent Easton + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License (LGPL) as published by the Free Software Foundation. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, copies are available + * at http://www.opensource.org. + */ + +package tdc; + +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.geom.Area; +import java.awt.geom.GeneralPath; +import java.awt.geom.Line2D; + +import terrain.TerrainHexGrid; +import VASSAL.build.module.map.boardPicker.board.mapgrid.HexGridNumbering; + +/** + * A class representing a Line of Sight on a map. Main purpose is to determine + * of the LOS runs along hex edges or not Co-ordinate system is Map Co-ordinates + * + * @author Brent + * + */ +public class LOS { + + protected TdcMap map; + protected Point p1, p2; + protected Gradient gradient; + protected Rectangle bounds; + protected Area shape; + + public LOS(TdcMap map, Point p1, Point p2) { + + this.map = map; + this.p1 = p1; + this.p2 = p2; + gradient = new Gradient(p1, p2); + bounds = new Rectangle(Math.min(p1.x, p2.x), Math.min(p1.y, p2.y), Math.abs(p2.x - p1.x), Math.abs(p2.y - p1.y)); + + } + + public String toString() { + return "LOS from "+p1.x+","+p1.y+" to "+p2.x+","+p2.y; + } + + public Point getStart() { + return p1; + } + + public Point getEnd() { + return p2; + } + + public boolean isSpinal() { + + boolean spinal = false; + + final TerrainHexGrid grid = map.findTerrainHexGrid(p1); + if (grid == null) + return spinal; + + final HexGridNumbering numbering = (HexGridNumbering) grid.getGridNumbering(); + if (numbering == null) + return spinal; + + final int col1 = numbering.getColumn(p1); + final int col2 = numbering.getColumn(p2); + final int row1 = numbering.getRow(p1); + final int row2 = numbering.getRow(p2); + + final int cd = col2 - col1; + final int rd = row2 - row1; + + // Spinal if rows are equal and columns are same parity + if (row1 == row2 && (col1 % 2) == (col2 % 2)) { + spinal = true; + } + + // From and to columns both even or both odd + else if ((col1 % 2) == (col2 % 2)) { + spinal = ((2 * rd) == (3 * cd)) || ((2 * rd) == (3 * -cd)); + } + + // From to Even to odd + else if ((col1 % 2) == 0 && (col2 % 2 == 1)) { + spinal = ((2 * rd + 1) == (3 * cd)) || ((2 * rd + 1) == (3 * -cd)); + } + + // From odd to even + else { + spinal = ((2 * rd - 1) == (3 * cd)) || ((2 * rd - 1) == (3 * -cd)); + } + + return spinal; + } + + // A Point is on the line if it is within the bounding box of the LOS and a + // line from the LOS origin to the point has the same gradient as the LOS + public boolean isOnLine(Point p) { + + double dist = Line2D.ptLineDistSq(p1.x, p1.y, p2.x, p2.y, p.x, p.y); + return Math.abs(dist) < 4f; + + } + + /* + * Area's can only be intersected with other areas, not a line, so turn this LOS + * into a very narrow Area + */ + public Area getLosShape() { + if (shape == null) { + final GeneralPath path = new GeneralPath(); + path.moveTo(p1.x, p1.y); + path.lineTo(p1.x - .1f, p1.y - .1f); + path.lineTo(p2.x - .1f, p2.y - .1f); + path.lineTo(p2.x, p2.y); + path.closePath(); + shape = new Area(path); + } + return shape; + } + + /* + * Does this LOS intersect the supplied Area? + */ + public boolean intersects (Area a) { + final Area los = new Area(getLosShape()); + los.intersect(a); + return ! los.isEmpty(); + } + + public boolean intersects (float x1, float y1, float x2, float y2) { + return Line2D.linesIntersect(x1, y1, x2, y2, getStart().x, getStart().y, getEnd().x, getEnd().y); + } +} Property changes on: VSQL-src/trunk/tdc/LOS.java ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Modified: VSQL-src/trunk/tdc/TdcMap.java =================================================================== --- VSQL-src/trunk/tdc/TdcMap.java 2015-05-18 03:46:31 UTC (rev 9194) +++ VSQL-src/trunk/tdc/TdcMap.java 2015-05-21 07:03:47 UTC (rev 9195) @@ -21,7 +21,7 @@ import java.awt.Point; import java.awt.geom.Point2D; -import java.util.List; +import java.util.Set; import qtree.QuadTreeException; import terrain.TerrainBasicPiece; @@ -155,7 +155,7 @@ } } - public void findBlockingTerrain (Point start, Point end, List<BlockingTerrain> blockingTerrain) { + public void findBlockingTerrain (Point start, Point end, Set<BlockingTerrain> blockingTerrain) { blockingTerrain.clear(); if (terrainMap != null) { terrainMap.findBlockingTerrain(start, end, blockingTerrain); Modified: VSQL-src/trunk/tdc/WizardThread.java =================================================================== --- VSQL-src/trunk/tdc/WizardThread.java 2015-05-18 03:46:31 UTC (rev 9194) +++ VSQL-src/trunk/tdc/WizardThread.java 2015-05-21 07:03:47 UTC (rev 9195) @@ -29,6 +29,8 @@ import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; import java.util.List; import javax.swing.KeyStroke; @@ -175,8 +177,18 @@ protected String currentNavalBox; // Name of naval box arrow is currently over protected GamePiece currentAssaultForceMarker; // Assault Force marker // matching curentNavalpark; - protected ArrayList<BlockingTerrain> blockingTerrain = new ArrayList<BlockingTerrain>(); + protected HashSet<BlockingTerrain> blockingTerrain = new HashSet<BlockingTerrain>(); + protected ColorConfigurer ridgeColorConfig; + protected ColorConfigurer crestColorConfig; + protected ColorConfigurer blockColorConfig; + protected ColorConfigurer possibleColorConfig; + + protected static final String RIDGE_COLOR = "ridgeColor"; + protected static final String CREST_COLOR = "crestColor"; + protected static final String BLOCK_COLOR = "blockColor"; + protected static final String POSSIBLE_COLOR = "possibleColor"; + public WizardThread(AttackWizard w) { myWizard = w; @@ -274,7 +286,38 @@ map.getView().addMouseMotionListener(this); map.addDrawComponent(this); GameModule.getGameModule().addCommandEncoder(this); + + ridgeColorConfig = new ColorConfigurer(RIDGE_COLOR, "Blocking Ridge Color", Color.ORANGE); + GameModule.getGameModule().getPrefs().addOption(AttackWizard.PREF_TAB, ridgeColorConfig); + + crestColorConfig = new ColorConfigurer(CREST_COLOR, "Blocking Crest Color", Color.YELLOW); + GameModule.getGameModule().getPrefs().addOption(AttackWizard.PREF_TAB, crestColorConfig); + + blockColorConfig = new ColorConfigurer(BLOCK_COLOR, "Blocking Hex Color", Color.RED); + GameModule.getGameModule().getPrefs().addOption(AttackWizard.PREF_TAB, blockColorConfig); + + possibleColorConfig = new ColorConfigurer(POSSIBLE_COLOR, "Possibly Blocking Hex Color", Color.PINK); + GameModule.getGameModule().getPrefs().addOption(AttackWizard.PREF_TAB, possibleColorConfig); + } + + public Color getRidgeColor() { + return (Color) ridgeColorConfig.getValue(); + } + + public Color getCrestColor() { + return (Color) crestColorConfig.getValue(); + } + + public Color getBlockColor() { + return (Color) blockColorConfig.getValue(); + } + + public Color getPossibleColor() { + return (Color) possibleColorConfig.getValue(); + } + + public void removeFrom(Buildable b) { map = (Map) b; @@ -514,14 +557,14 @@ // Draw Hex Blocking terrain for (BlockingTerrain bt : blockingTerrain) { if (bt instanceof HexBlockingTerrain) { - bt.draw (g); + bt.draw (g, this); } } // Draw Edge Blocking terrain for (BlockingTerrain bt : blockingTerrain) { if (bt instanceof EdgeBlockingTerrain) { - bt.draw (g); + bt.draw (g, this); } } @@ -701,7 +744,7 @@ indirectSource = null; indirectAnchor = null; addRange = 0; - myWizard.targetSelected(arrow, range); + myWizard.targetSelected(arrow, range, this); } lastRelease = e.getWhen(); @@ -891,6 +934,27 @@ protected void findLOSBlockingTerrain() { ((TdcMap) map).findBlockingTerrain(anchor, arrow, blockingTerrain); } + + protected String getBlockingReasons() { + ArrayList<String> reasons = new ArrayList<String>(); + for (BlockingTerrain bt : blockingTerrain) { + for (Iterator<String> i = bt.getReasons(); i.hasNext(); ) { + String reason = i.next(); + if (! reasons.contains(reason)) reasons.add(reason); + } + } + StringBuffer s = new StringBuffer(); + for (String reason : reasons) { + if (s.length() > 0) s.append(", "); + s.append(reason); + } + + return s.toString(); + } + + public boolean isBlocked() { + return blockingTerrain.size() > 0; + } public static String getConfigureTypeName() { return "Line of Sight Thread"; Modified: VSQL-src/trunk/terrain/TerrainEdge.java =================================================================== --- VSQL-src/trunk/terrain/TerrainEdge.java 2015-05-18 03:46:31 UTC (rev 9194) +++ VSQL-src/trunk/terrain/TerrainEdge.java 2015-05-21 07:03:47 UTC (rev 9195) @@ -26,65 +26,58 @@ /** * Concrete implementation of Edge Terrain */ -public class TerrainEdge { +public class TerrainEdge { - private static final long serialVersionUID = 1L; protected static final String TYPE = "e"; protected EdgeRef reference; protected EdgeTerrain terrain; protected TerrainHexGrid grid; - public TerrainEdge (int c1, int r1, int c2, int r2, EdgeTerrain t, Point c, TerrainHexGrid g) { - reference = new EdgeRef(c1, r1, c2, r2, grid); - reference.setCenter(new Point2D.Float(c.x, c.y)); + public TerrainEdge(int c1, int r1, int c2, int r2, EdgeTerrain t, Point c, TerrainHexGrid g) { + reference = new EdgeRef(c1, r1, c2, r2, grid); + reference.setCenter(new Point2D.Float(c.x, c.y)); grid = g; terrain = t; - System.out.println("A: "+t.getTerrainName()+": "+c.x+", "+c.y+", "+c1+"."+r1+"/"+c2+"."+r2); } - - - - public TerrainEdge (EdgeRef ref, EdgeTerrain t) { - reference = ref; - terrain = t; - System.out.println("B: "+t.getTerrainName()+" "+ref.toString()); - } - - public TerrainEdge (Point centerPos, TerrainHexGrid g, EdgeTerrain t) { + + public TerrainEdge(EdgeRef ref, EdgeTerrain t) { + reference = ref; + terrain = t; + } + + public TerrainEdge(Point centerPos, TerrainHexGrid g, EdgeTerrain t) { reference = new EdgeRef(new Point2D.Float(centerPos.x, centerPos.y), g); - terrain = t; + terrain = t; grid = g; - System.out.println("C: "+t.getTerrainName()+" "+reference.toString()); } - + public TerrainEdge(String code, TerrainHexGrid grid) { decode(code, grid); - System.out.println("D: "+terrain.getTerrainName()+" "+reference.toString()); } - + public boolean equals(Object o) { if (o instanceof TerrainEdge) { return ((TerrainEdge) o).getLocation().equals(getLocation()); } return false; } - + public EdgeRef getReference() { return reference; } - + public void recalculate() { reference.invalidate(); } - + public Point2D.Float getEnd1() { return reference.getEnd1(); } - + public Point2D.Float getEnd2() { return reference.getEnd2(); } - + public EdgeRef getLocation() { return reference; } @@ -92,23 +85,23 @@ public EdgeRef getReverseLocation() { return reference.reversed(); } - + public TerrainEdge reversed() { return new TerrainEdge(reference.reversed(), terrain); } - + public Point2D.Float getCenter() { return reference.getCenter(); } - + public void setTerrain(EdgeTerrain t) { - terrain = t; + terrain = t; } - + public EdgeTerrain getTerrain() { return terrain; } - + public String encode() { final SequenceEncoder se = new SequenceEncoder(TYPE, ','); se.append(reference.getColumn()); @@ -118,11 +111,11 @@ se.append(terrain == null ? "" : terrain.getTerrainName()); return se.getValue(); } - + public void decode(String code, TerrainHexGrid grid) { final SequenceEncoder.Decoder sd = new SequenceEncoder.Decoder(code, ','); sd.nextToken(); reference = new EdgeRef(sd.nextInt(0), sd.nextInt(0), sd.nextInt(0), sd.nextInt(0), grid); - terrain = (EdgeTerrain) TerrainDefinitions.getInstance().getEdgeTerrainDefinitions().getTerrain(sd.nextToken(TerrainMap.NO_TERRAIN)); + terrain = (EdgeTerrain) TerrainDefinitions.getInstance().getEdgeTerrainDefinitions().getTerrain(sd.nextToken(TerrainMap.NO_TERRAIN)); } } Modified: VSQL-src/trunk/terrain/TerrainHexGrid.java =================================================================== --- VSQL-src/trunk/terrain/TerrainHexGrid.java 2015-05-18 03:46:31 UTC (rev 9194) +++ VSQL-src/trunk/terrain/TerrainHexGrid.java 2015-05-21 07:03:47 UTC (rev 9195) @@ -18,13 +18,11 @@ */ package terrain; -import static java.lang.Math.abs; import static java.lang.Math.floor; -import static java.lang.Math.max; -import static java.lang.Math.min; import static java.lang.Math.round; import java.awt.Point; +import java.awt.Polygon; import java.awt.Rectangle; import java.awt.geom.Area; import java.awt.geom.Point2D; @@ -50,6 +48,7 @@ return container == null ? null : container.getBoard(); } + // Note x, y is in Board co-ords, not Map co-ords public Area getSingleHex(int x, int y) { return getSingleHexShape(x, y, false); } @@ -64,6 +63,71 @@ return getSingleHex(p.x, p.y); } + public Area getSingleFatHex(TerrainHex t) { + final Point p = getHexCenter(t.getColumn(), t.getRow()); + Point[] points = getFatHexVertices(p.x, p.y); + Polygon poly = new Polygon(); + for (int i = 0; i < points.length; i++) { + poly.addPoint(points[i].x, points[i].y); + } + poly.addPoint(points[0].x, points[0].y); + return new Area(poly); + } + + // Return the vertices of a fat Hex in Board co-ordinates + public Point[] getFatHexVertices(int centerX, int centerY) { + + final int fatness = 5; + + Point[] points = new Point[6]; + boolean reversed = false; + + float x = (float) (sideways ? centerY : centerX); + float y = (float) (sideways ? centerX : centerY); + + float x1,y1, x2,y2, x3,y3, x4, y4, x5, y5, x6, y6; + + float deltaX = (float) (this.dx); + float deltaY = (float) (this.dy); + + float r = 2.F * deltaX / 3.F; + + for (int i = 0; i < 6; i++) { + points[i] = new Point(); + } + + x1 = x - r; + y1 = y; + points[0].setLocation(round(x1)-fatness, round(y1)); + + x2 = x - 0.5F * r; + y2 = reversed ? y + 0.5F * deltaY : y - 0.5F * deltaY; + points[1].setLocation(round(x2)-fatness, round(y2)-fatness); + + x3 = x + 0.5F * r; + y3 = y2; + points[2].setLocation(round(x3) + 1 + fatness, round(y3)-fatness); + + x4 = x + r; + y4 = y; + points[3].setLocation(round(x4) + 1 + fatness, round(y4)); + + x5 = x3; + y5 = reversed ? y - 0.5F * deltaY : y + 0.5F * deltaY; + points[4].setLocation(round(x5) + 1 + fatness, round(y5) + 1 + fatness); + + x6 = x2; + y6 = y5; + points[5].setLocation(round(x6)-fatness, round(y6) + 1 + fatness); + + if (sideways) { + for (int i = 0; i < 6; i++) { + rotate(points[i]); + } + } + + return points; + } /* * Return the terrain at the given map x,y point (in Global Map coordinates) */ Modified: VSQL-src/trunk/terrain/TerrainMap.java =================================================================== --- VSQL-src/trunk/terrain/TerrainMap.java 2015-05-18 03:46:31 UTC (rev 9194) +++ VSQL-src/trunk/terrain/TerrainMap.java 2015-05-21 07:03:47 UTC (rev 9195) @@ -18,7 +18,6 @@ */ package terrain; -import java.awt.Point; import java.awt.geom.Area; import java.awt.geom.GeneralPath; import java.awt.geom.Point2D; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |