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
This commit is contained in:
Walter Korman
2001-08-03 22:23:47 +00:00
parent 4a1e7458bb
commit 17e402121c
4 changed files with 279 additions and 70 deletions
@@ -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; package com.threerings.miso.sprite;
@@ -19,14 +19,15 @@ public class Path
public static final int NUM_DIRECTIONS = 8; public static final int NUM_DIRECTIONS = 8;
/** Direction constants. */ /** Direction constants. */
public static final int DIR_SOUTH = 0; public static final int DIR_NONE = -1;
public static final int DIR_SOUTHWEST = 1; public static final int DIR_SOUTHWEST = 0;
public static final int DIR_WEST = 2; public static final int DIR_WEST = 1;
public static final int DIR_NORTHWEST = 3; public static final int DIR_NORTHWEST = 2;
public static final int DIR_NORTH = 4; public static final int DIR_NORTH = 3;
public static final int DIR_NORTHEAST = 5; public static final int DIR_NORTHEAST = 4;
public static final int DIR_EAST = 6; public static final int DIR_EAST = 5;
public static final int DIR_SOUTHEAST = 7; public static final int DIR_SOUTHEAST = 6;
public static final int DIR_SOUTH = 7;
/** /**
* Construct a <code>Path</code> object. * Construct a <code>Path</code> object.
@@ -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; package com.threerings.miso.scene;
@@ -7,20 +7,19 @@ import com.threerings.miso.Log;
import com.threerings.miso.sprite.*; import com.threerings.miso.sprite.*;
import com.threerings.miso.tile.Tile; import com.threerings.miso.tile.Tile;
import com.threerings.miso.tile.TileManager; import com.threerings.miso.tile.TileManager;
import com.threerings.miso.util.MathUtil;
import java.awt.*; import java.awt.*;
import java.awt.image.*; import java.awt.image.*;
import java.util.ArrayList; import java.util.ArrayList;
/** /**
* The IsoSceneView provides an isometric graphics view of a * The <code>IsoSceneView</code> provides an isometric view of a
* particular scene. * particular scene.
*/ */
public class IsoSceneView implements EditableSceneView public class IsoSceneView implements EditableSceneView
{ {
/** /**
* Construct an IsoSceneView object. * Construct an <code>IsoSceneView</code> object.
* *
* @param tilemgr the tile manager. * @param tilemgr the tile manager.
* @param spritemgr the sprite manager. * @param spritemgr the sprite manager.
@@ -125,7 +124,7 @@ public class IsoSceneView implements EditableSceneView
{ {
// get the top-left screen coordinate for the tile // get the top-left screen coordinate for the tile
Point spos = new Point(); Point spos = new Point();
tileToScreen(x, y, spos); IsoUtil.tileToScreen(_model, x, y, spos);
// create a polygon framing the tile // create a polygon framing the tile
Polygon poly = new Polygon(); Polygon poly = new Polygon();
@@ -279,7 +278,7 @@ public class IsoSceneView implements EditableSceneView
public void setHighlightedTile (int sx, int sy) 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) public void invalidateScreenRect (int x, int y, int width, int height)
{ {
Point tpos = new Point(); Point tpos = new Point();
screenToTile(x, y, tpos); IsoUtil.screenToTile(_model, x, y, tpos);
// Log.info("invalidateScreenRect: mapped rect to tile " + // Log.info("invalidateScreenRect: mapped rect to tile " +
// "[tx=" + tpos.x + ", ty=" + tpos.y + // "[tx=" + tpos.x + ", ty=" + tpos.y +
@@ -318,54 +317,6 @@ public class IsoSceneView implements EditableSceneView
_dirty.add(new int[] { tpos.x, tpos.y }); _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) public void setScene (Scene scene)
{ {
_scene = scene; _scene = scene;
@@ -379,7 +330,7 @@ public class IsoSceneView implements EditableSceneView
public void setTile (int x, int y, int lnum, Tile tile) public void setTile (int x, int y, int lnum, Tile tile)
{ {
Point tpos = new Point(); Point tpos = new Point();
screenToTile(x, y, tpos); IsoUtil.screenToTile(_model, x, y, tpos);
_scene.tiles[tpos.x][tpos.y][lnum] = tile; _scene.tiles[tpos.x][tpos.y][lnum] = tile;
} }
@@ -399,7 +350,8 @@ public class IsoSceneView implements EditableSceneView
// create path from current loc to destination // create path from current loc to destination
Path path = new Path(sprite.x, sprite.y); 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; return path;
} }
@@ -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; package com.threerings.miso.scene;
@@ -23,6 +23,9 @@ public class IsoSceneModel
/** Tile dimensions and half-dimensions in the view. */ /** Tile dimensions and half-dimensions in the view. */
public int tilewid, tilehei, tilehwid, tilehhei; 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. */ /** The bounds dimensions for the view. */
public Dimension bounds; public Dimension bounds;
@@ -44,6 +47,15 @@ public class IsoSceneModel
/** The last calculated x- and y-axis mouse position tracking lines. */ /** The last calculated x- and y-axis mouse position tracking lines. */
public Point lineX[], lineY[]; 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. */ /** Whether tile coordinates should be drawn. */
public boolean showCoords; public boolean showCoords;
@@ -53,11 +65,24 @@ public class IsoSceneModel
public IsoSceneModel () public IsoSceneModel ()
{ {
setTileDimensions(32, 16); setTileDimensions(32, 16);
setFineGranularity(4);
setBounds(600, 600); setBounds(600, 600);
setOrigin(bounds.width / 2, -(9 * tilehei)); setOrigin(bounds.width / 2, -(9 * tilehei));
showCoords = false; 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 * Set the dimensions of the tiles that comprise the base layer of
* the isometric view and therefore drive the view geometry as a * 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 * Pre-calculate the x-axis lines for later use in converting
* x-axis) for later use in converting screen coordinates to tile * screen coordinates to tile coordinates and tile-based pixel
* coordinates. * coordinates to fine coordinates.
*/ */
public void calculateXAxis () public void calculateXAxis ()
{ {
// first calculate scene-based x-axis line for conversion from
// screen to tile coordinates
// create the x- and y-axis lines // create the x- and y-axis lines
lineX = new Point[2]; lineX = new Point[2];
lineY = new Point[2]; lineY = new Point[2];
@@ -145,5 +173,16 @@ public class IsoSceneModel
// determine the ending point // determine the ending point
lineX[1].x = lineX[0].x + (tilehwid * Scene.TILE_WIDTH); lineX[1].x = lineX[0].x + (tilehwid * Scene.TILE_WIDTH);
lineX[1].y = lineX[0].y + (int)((slopeX * lineX[1].x) + bX); 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;
} }
} }
@@ -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 <code>IsoUtil</code> 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 <code>Path</code>
* 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 <code>Path</code>
* class's direction constants, or <code>Path.DIR_NONE</code>
* 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;
}