From 17e402121cba6ef33bf081d8338317ec882d91b2 Mon Sep 17 00:00:00 2001 From: Walter Korman Date: Fri, 3 Aug 2001 22:23:47 +0000 Subject: [PATCH] Determine proper compass direction to assign path nodes. Added conversion routines for fine and full coordinates, and moved iso-related utility functions to IsoUtil. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@167 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- .../media/util/LineSegmentPath.java | 19 +- .../threerings/miso/client/IsoSceneView.java | 66 +----- .../miso/client/IsoSceneViewModel.java | 47 +++- .../com/threerings/miso/client/IsoUtil.java | 217 ++++++++++++++++++ 4 files changed, 279 insertions(+), 70 deletions(-) create mode 100644 src/java/com/threerings/miso/client/IsoUtil.java diff --git a/src/java/com/threerings/media/util/LineSegmentPath.java b/src/java/com/threerings/media/util/LineSegmentPath.java index f1d15d972..e88ee8989 100644 --- a/src/java/com/threerings/media/util/LineSegmentPath.java +++ b/src/java/com/threerings/media/util/LineSegmentPath.java @@ -1,5 +1,5 @@ // -// $Id: LineSegmentPath.java,v 1.3 2001/08/02 21:02:56 shaper Exp $ +// $Id: LineSegmentPath.java,v 1.4 2001/08/03 22:23:47 shaper Exp $ package com.threerings.miso.sprite; @@ -19,14 +19,15 @@ public class Path public static final int NUM_DIRECTIONS = 8; /** Direction constants. */ - public static final int DIR_SOUTH = 0; - public static final int DIR_SOUTHWEST = 1; - public static final int DIR_WEST = 2; - public static final int DIR_NORTHWEST = 3; - public static final int DIR_NORTH = 4; - public static final int DIR_NORTHEAST = 5; - public static final int DIR_EAST = 6; - public static final int DIR_SOUTHEAST = 7; + public static final int DIR_NONE = -1; + public static final int DIR_SOUTHWEST = 0; + public static final int DIR_WEST = 1; + public static final int DIR_NORTHWEST = 2; + public static final int DIR_NORTH = 3; + public static final int DIR_NORTHEAST = 4; + public static final int DIR_EAST = 5; + public static final int DIR_SOUTHEAST = 6; + public static final int DIR_SOUTH = 7; /** * Construct a Path object. diff --git a/src/java/com/threerings/miso/client/IsoSceneView.java b/src/java/com/threerings/miso/client/IsoSceneView.java index baf80c6cd..f7540ae65 100644 --- a/src/java/com/threerings/miso/client/IsoSceneView.java +++ b/src/java/com/threerings/miso/client/IsoSceneView.java @@ -1,5 +1,5 @@ // -// $Id: IsoSceneView.java,v 1.23 2001/08/02 20:43:03 shaper Exp $ +// $Id: IsoSceneView.java,v 1.24 2001/08/03 22:23:47 shaper Exp $ package com.threerings.miso.scene; @@ -7,20 +7,19 @@ import com.threerings.miso.Log; import com.threerings.miso.sprite.*; import com.threerings.miso.tile.Tile; import com.threerings.miso.tile.TileManager; -import com.threerings.miso.util.MathUtil; import java.awt.*; import java.awt.image.*; import java.util.ArrayList; /** - * The IsoSceneView provides an isometric graphics view of a + * The IsoSceneView provides an isometric view of a * particular scene. */ public class IsoSceneView implements EditableSceneView { /** - * Construct an IsoSceneView object. + * Construct an IsoSceneView object. * * @param tilemgr the tile manager. * @param spritemgr the sprite manager. @@ -125,7 +124,7 @@ public class IsoSceneView implements EditableSceneView { // get the top-left screen coordinate for the tile Point spos = new Point(); - tileToScreen(x, y, spos); + IsoUtil.tileToScreen(_model, x, y, spos); // create a polygon framing the tile Polygon poly = new Polygon(); @@ -279,7 +278,7 @@ public class IsoSceneView implements EditableSceneView public void setHighlightedTile (int sx, int sy) { - screenToTile(sx, sy, _htile); + IsoUtil.screenToTile(_model, sx, sy, _htile); } /** @@ -308,7 +307,7 @@ public class IsoSceneView implements EditableSceneView public void invalidateScreenRect (int x, int y, int width, int height) { Point tpos = new Point(); - screenToTile(x, y, tpos); + IsoUtil.screenToTile(_model, x, y, tpos); // Log.info("invalidateScreenRect: mapped rect to tile " + // "[tx=" + tpos.x + ", ty=" + tpos.y + @@ -318,54 +317,6 @@ public class IsoSceneView implements EditableSceneView _dirty.add(new int[] { tpos.x, tpos.y }); } - /** - * Convert the given screen-based pixel coordinates to their - * corresponding tile-based coordinates. Converted coordinates - * are placed in the given point object. - * - * @param sx the screen x-position pixel coordinate. - * @param sy the screen y-position pixel coordinate. - * @param tpos the point object to place coordinates in. - */ - protected void screenToTile (int sx, int sy, Point tpos) - { - Point[] lx = _model.lineX, ly = _model.lineY; - - // calculate line parallel to the y-axis (from mouse pos to x-axis) - ly[0].setLocation(sx, sy); - int bY = (int)(sy - (_model.slopeY * sx)); - - // determine intersection of x- and y-axis lines - ly[1].x = (int)((bY - (_model.bX + _model.origin.y)) / - (_model.slopeX - _model.slopeY)); - ly[1].y = (int)((_model.slopeY * ly[1].x) + bY); - - // determine distance of mouse pos along the x axis - int xdist = (int) MathUtil.distance( - lx[0].x, lx[0].y, ly[1].x, ly[1].y); - tpos.x = (int)(xdist / _model.tilelen); - - // determine distance of mouse pos along the y-axis - int ydist = (int) MathUtil.distance( - ly[0].x, ly[0].y, ly[1].x, ly[1].y); - tpos.y = (int)(ydist / _model.tilelen); - } - - /** - * Convert the given tile-based coordinates to their corresponding - * screen-based pixel coordinates. Converted coordinates are - * placed in the given point object. - * - * @param x the tile x-position coordinate. - * @param y the tile y-position coordinate. - * @param spos the point object to place coordinates in. - */ - protected void tileToScreen (int x, int y, Point spos) - { - spos.x = _model.origin.x + ((x - y - 1) * _model.tilehwid); - spos.y = _model.origin.y + ((x + y) * _model.tilehhei); - } - public void setScene (Scene scene) { _scene = scene; @@ -379,7 +330,7 @@ public class IsoSceneView implements EditableSceneView public void setTile (int x, int y, int lnum, Tile tile) { Point tpos = new Point(); - screenToTile(x, y, tpos); + IsoUtil.screenToTile(_model, x, y, tpos); _scene.tiles[tpos.x][tpos.y][lnum] = tile; } @@ -399,7 +350,8 @@ public class IsoSceneView implements EditableSceneView // create path from current loc to destination Path path = new Path(sprite.x, sprite.y); - path.addNode(x, y, Path.DIR_NORTH); + int dir = IsoUtil.getDirection(_model, sprite.x, sprite.y, x, y); + path.addNode(x, y, dir); return path; } diff --git a/src/java/com/threerings/miso/client/IsoSceneViewModel.java b/src/java/com/threerings/miso/client/IsoSceneViewModel.java index ebc460913..aba05f662 100644 --- a/src/java/com/threerings/miso/client/IsoSceneViewModel.java +++ b/src/java/com/threerings/miso/client/IsoSceneViewModel.java @@ -1,5 +1,5 @@ // -// $Id: IsoSceneViewModel.java,v 1.2 2001/08/02 05:08:23 shaper Exp $ +// $Id: IsoSceneViewModel.java,v 1.3 2001/08/03 22:23:47 shaper Exp $ package com.threerings.miso.scene; @@ -23,6 +23,9 @@ public class IsoSceneModel /** Tile dimensions and half-dimensions in the view. */ public int tilewid, tilehei, tilehwid, tilehhei; + /** Number of fine coordinates on each axis within a tile. */ + public int finegran; + /** The bounds dimensions for the view. */ public Dimension bounds; @@ -44,6 +47,15 @@ public class IsoSceneModel /** The last calculated x- and y-axis mouse position tracking lines. */ public Point lineX[], lineY[]; + /** The length between fine coordinates in pixels. */ + public float finelen; + + /** The y-intercept of the x-axis line within a tile. */ + public float fineBX; + + /** The slope of the x- and y-axis lines within a tile. */ + public float fineSlopeX, fineSlopeY; + /** Whether tile coordinates should be drawn. */ public boolean showCoords; @@ -53,11 +65,24 @@ public class IsoSceneModel public IsoSceneModel () { setTileDimensions(32, 16); + setFineGranularity(4); setBounds(600, 600); setOrigin(bounds.width / 2, -(9 * tilehei)); showCoords = false; } + /** + * Set the number of fine coordinates within a tile. The + * granularity determines the number of coordinates on both the x- + * and y-axis. + * + * @param gran the number of fine coordinates on each axis. + */ + public void setFineGranularity (int gran) + { + finegran = gran; + } + /** * Set the dimensions of the tiles that comprise the base layer of * the isometric view and therefore drive the view geometry as a @@ -124,12 +149,15 @@ public class IsoSceneModel } /** - * Pre-calculate the x-axis line (from tile origin to right end of - * x-axis) for later use in converting screen coordinates to tile - * coordinates. + * Pre-calculate the x-axis lines for later use in converting + * screen coordinates to tile coordinates and tile-based pixel + * coordinates to fine coordinates. */ public void calculateXAxis () { + // first calculate scene-based x-axis line for conversion from + // screen to tile coordinates + // create the x- and y-axis lines lineX = new Point[2]; lineY = new Point[2]; @@ -145,5 +173,16 @@ public class IsoSceneModel // determine the ending point lineX[1].x = lineX[0].x + (tilehwid * Scene.TILE_WIDTH); lineX[1].y = lineX[0].y + (int)((slopeX * lineX[1].x) + bX); + + // next calculate tile-based x-axis line for conversion from + // tile-based pixel to fine coordinates + + // calculate the edge length separating each fine coordinate + finelen = tilelen / (float)finegran; + + // calculate the x-axis line + fineSlopeX = (float)tilehei / (float)tilewid; + fineBX = -(fineSlopeX * (float)tilehwid); + fineSlopeY = -fineSlopeX; } } diff --git a/src/java/com/threerings/miso/client/IsoUtil.java b/src/java/com/threerings/miso/client/IsoUtil.java new file mode 100644 index 000000000..f97ba06dd --- /dev/null +++ b/src/java/com/threerings/miso/client/IsoUtil.java @@ -0,0 +1,217 @@ +// +// $Id: IsoUtil.java,v 1.1 2001/08/03 22:23:47 shaper Exp $ + +package com.threerings.miso.scene; + +import java.awt.Point; + +import com.threerings.miso.sprite.Path; +import com.threerings.miso.util.MathUtil; + +/** + * The IsoUtil class is a holding place for miscellaneous + * isometric-display-related utility routines. + */ +public class IsoUtil +{ + /** + * Given two points in screen pixel coordinates, return the + * compass direction that point B lies in from point A from an + * isometric perspective. + * + * @param ax the x-position of point A. + * @param ay the y-position of point A. + * @param bx the x-position of point B. + * @param by the y-position of point B. + * + * @return the direction specified as one of the Path + * class's direction constants. + */ + public static int getDirection ( + IsoSceneModel model, int ax, int ay, int bx, int by) + { + Point afpos = new Point(), bfpos = new Point(); + + // convert screen coordinates to full coordinates to get both + // tile coordinates and fine coordinates + screenToFull(model, ax, ay, afpos); + screenToFull(model, bx, by, bfpos); + + // pull out the tile coordinates for each point + int tax = afpos.x / FULL_TILE_FACTOR; + int tay = afpos.y / FULL_TILE_FACTOR; + + int tbx = bfpos.x / FULL_TILE_FACTOR; + int tby = bfpos.y / FULL_TILE_FACTOR; + + // compare tile coordinates to determine direction + int dir = getIsoDirection(model, tax, tay, tbx, tby); + if (dir != Path.DIR_NONE) return dir; + + // destination point is in the same tile as the + // origination point, so consider fine coordinates + + // pull out the fine coordinates for each point + int fax = afpos.x - (tax * FULL_TILE_FACTOR); + int fay = afpos.y - (tay * FULL_TILE_FACTOR); + + int fbx = bfpos.x - (tbx * FULL_TILE_FACTOR); + int fby = bfpos.y - (tby * FULL_TILE_FACTOR); + + // compare fine coordinates to determine direction + dir = getIsoDirection(model, fax, fay, fbx, fby); + + // arbitrarily return southwest if fine coords were also equivalent + return (dir == -1) ? Path.DIR_SOUTHWEST : dir; + } + + /** + * Given two points in an isometric coordinate system, return the + * compass direction that point B lies in from point A. This + * method is used to determine direction for both tile coordinates + * and fine coordinates within a tile, since the coordinate + * systems are the same. + * + * @param ax the x-position of point A. + * @param ay the y-position of point A. + * @param bx the x-position of point B. + * @param by the y-position of point B. + * + * @return the direction specified as one of the Path + * class's direction constants, or Path.DIR_NONE + * if point B is equivalent to point A. + */ + public static int getIsoDirection ( + IsoSceneModel model, int ax, int ay, int bx, int by) + { + if (bx > ax) { + if (by == ay) return Path.DIR_SOUTH; + return (by < ay) ? Path.DIR_SOUTHEAST : Path.DIR_SOUTHWEST; + + } else if (bx == ax) { + if (by == ay) return Path.DIR_NONE; + return (by < ay) ? Path.DIR_EAST : Path.DIR_WEST; + + } else { // bx < ax + if (by == ay) return Path.DIR_NORTH; + return (by < ay) ? Path.DIR_NORTHEAST : Path.DIR_NORTHWEST; + } + } + + /** + * Convert the given screen-based pixel coordinates to their + * corresponding tile-based coordinates. Converted coordinates + * are placed in the given point object. + * + * @param sx the screen x-position pixel coordinate. + * @param sy the screen y-position pixel coordinate. + * @param tpos the point object to place coordinates in. + */ + public static void screenToTile ( + IsoSceneModel model, int sx, int sy, Point tpos) + { + Point[] lx = model.lineX, ly = model.lineY; + + // calculate line parallel to the y-axis (from mouse pos to x-axis) + ly[0].setLocation(sx, sy); + int bY = (int)(sy - (model.slopeY * sx)); + + // determine intersection of x- and y-axis lines + ly[1].x = (int)((bY - (model.bX + model.origin.y)) / + (model.slopeX - model.slopeY)); + ly[1].y = (int)((model.slopeY * ly[1].x) + bY); + + // determine distance of mouse pos along the x axis + int xdist = (int) MathUtil.distance( + lx[0].x, lx[0].y, ly[1].x, ly[1].y); + tpos.x = (int)(xdist / model.tilelen); + + // determine distance of mouse pos along the y-axis + int ydist = (int) MathUtil.distance( + ly[0].x, ly[0].y, ly[1].x, ly[1].y); + tpos.y = (int)(ydist / model.tilelen); + } + + /** + * Convert the given tile-based coordinates to their corresponding + * screen-based pixel coordinates. Converted coordinates are + * placed in the given point object. + * + * @param x the tile x-position coordinate. + * @param y the tile y-position coordinate. + * @param spos the point object to place coordinates in. + */ + public static void tileToScreen ( + IsoSceneModel model, int x, int y, Point spos) + { + spos.x = model.origin.x + ((x - y - 1) * model.tilehwid); + spos.y = model.origin.y + ((x + y) * model.tilehhei); + } + + /** + * Convert the given pixel coordinates, whose origin is at the + * top-left of a tile's containing rectangle, to fine coordinates + * within that tile. Converted coordinates are placed in the + * given point object. + * + * @param x the x-position pixel coordinate. + * @param y the y-position pixel coordinate. + * @param fpos the point object to place coordinates in. + */ + public static void pixelToFine ( + IsoSceneModel model, int x, int y, Point fpos) + { + // calculate line parallel to the y-axis (from the given + // x/y-pos to the x-axis) + float bY = y - (model.fineSlopeY * x); + + // determine intersection of x- and y-axis lines + int crossx = (int)((bY - model.fineBX) / + (model.fineSlopeX - model.fineSlopeY)); + int crossy = (int)((model.fineSlopeY * crossx) + bY); + + // TODO: final position should check distance between our + // position and the surrounding fine coords and return the + // actual closest fine coord, rather than just dividing. + + // determine distance along the x-axis + float xdist = MathUtil.distance(model.tilehwid, 0, crossx, crossy); + fpos.x = (int)(xdist / model.finelen); + + // determine distance along the y-axis + float ydist = MathUtil.distance(x, y, crossx, crossy); + fpos.y = (int)(ydist / model.finelen); + } + + /** + * Convert the given screen-based pixel coordinates to full + * scene-based coordinates that include both the tile coordinates + * and the fine coordinates in each dimension. Converted + * coordinates are placed in the given point object. + * + * @param sx the screen x-position pixel coordinate. + * @param sy the screen y-position pixel coordinate. + * @param fpos the point object to place coordinates in. + */ + public static void screenToFull ( + IsoSceneModel model, int sx, int sy, Point fpos) + { + // get the tile coordinates + Point tpos = new Point(); + screenToTile(model, sx, sy, tpos); + + // get the screen coordinates for the containing tile + Point spos = new Point(); + tileToScreen(model, tpos.x, tpos.y, spos); + + // get the fine coordinates within the containing tile + pixelToFine(model, sx - spos.x, sy - spos.y, fpos); + + // toss in the tile coordinates for good measure + fpos.x += (tpos.x * FULL_TILE_FACTOR); + fpos.y += (tpos.y * FULL_TILE_FACTOR); + } + + /** Multiplication factor to embed tile coords in full coords. */ + protected static final int FULL_TILE_FACTOR = 100; +}