Solving for lat or lon in Halversine? - gis

I need a function that returns a longitude value given a lat/lon coordinate, a distance in miles, and an intersecting latitude. To do that I need to use Halversine, like discussed here:
https://stackoverflow.com/a/7179026/78202. I realize that there will be two longitudes that intersect a given latitude a given distance from another ordered pair, I'd just like to get the point where I have a function that correctly returns one of them and I'll decide how to break the tie then.
I casually solved Holversine for lon1, and here's what I have. This is partly a math question, partly a programming question - what is wrong with this? There's no syntax error, I'm just not getting what I expect (see below).
function toRad(Value) {
/** Converts numeric degrees to radians */
return Value * Math.PI / 180;
}
/** returns the longitude a certain number of miles from another point given a latitude. **/
function getLon(miles, lat1, lat2, lon2) {
// see http://www.movable-type.co.uk/scripts/latlong.html
//Radius of the earth in: 1.609344 miles, 6371 km | var R = (6371 / 1.609344);
var R = 3958.7558657440545; // Radius of earth in Miles
miles = (typeof miles === "undefined") ? 1.46628357399041 : miles;
lat1 = (typeof lat1 === "undefined") ? 42.34769 : lat1;
lat2 = (typeof lat2 === "undefined") ? 42.367137 : lat2;
lon2 = (typeof lon2 === "undefined") ? -71.124383 : lon2;
var dLat = toRad( lat2-lat1 );
var sinInsideN1 = Math.sin(dLat);
var sinInsideN2 = Math.sin(miles/2*R);
var n1 = Math.pow(sinInsideN1,2);
var n2 = Math.pow(sinInsideN2,2);
var d1 = Math.cos(lat1)*Math.cos(lat2);
var inArcsin = Math.sqrt((n2-n1)/d1);
var translation = inArcsin-Math.floor(inArcsin);
var ret = -(lat1+2*Math.asin(translation))
return ret; // should be 42.34769
}
I'm getting 42.242513701215, which forms a coordinate with 42.34769 that is 8.63065661614176 mi from (42.367137,-71.124383), not 1.46628357399041 mi as expected.

I found an C-implementation of Haversine here http://code.google.com/p/siklon/source/browse/trunk/source/Haversine.c?r=11, which I have then rewritten wrt lon1:
#include <math.h>
/*Earth Radius in Kilometers.*/
/* static const double R = 6372.797560856; */
/*Earth Radius in Miles.*/
static const double R = 3958.7558657440545;
/*Degree vs. Radian conservation variables*/
static const double DEG_TO_RAD = M_PI/180.0;
static const double RAD_TO_DEG = 180.0/M_PI;
double Haversine_Distance(double lat1,double lon1, double lat2, double lon2)
{
double dlon = (lon2 - lon1) * DEG_TO_RAD;
double dlat = (lat2 - lat1) * DEG_TO_RAD;
double a = pow(sin(dlat * 0.5),2) + cos(lat1*DEG_TO_RAD) * cos(lat2*DEG_TO_RAD) * pow(sin(dlon * 0.5),2);
double c = 2.0 * atan2(sqrt(a), sqrt(1-a));
return R * c;
}
double inverseHaversine_Distance_lon1(double lat1, double dist, double lat2, double lon2)
{
/* Rewrite Haversine_Distance wrt lon1: */
/* dist = R * c = R * 2.0 * atan2(sqrt(a), sqrt(1-a)) */
/* dist / R / 2.0 = atan2(sqrt(a), sqrt(1-a)) */
/* sqrt(a) = sin(dist / R / 2.0); sqrt(1-a) = cos(dist / R / 2.0) */
/* a = (sin(dist / R / 2.0))^2; 1 - a = (cos(dist / R / 2.0))^2 */
/* pow(sin(dlat * 0.5),2) + cos(lat1*DEG_TO_RAD) * cos(lat2*DEG_TO_RAD) * pow(sin(dlon * 0.5),2) = (sin(dist / R / 2.0))^2 */
/* cos(lat1*DEG_TO_RAD) * cos(lat2*DEG_TO_RAD) * pow(sin(dlon * 0.5),2) = (sin(dist / R / 2.0))^2 - pow(sin(dlat * 0.5),2) */
/* pow(sin(dlon * 0.5),2) = (pow(sin(dist / R / 2.0), 2) - pow(sin(dlat * 0.5), 2)) / (cos(lat1*DEG_TO_RAD) * cos(lat2*DEG_TO_RAD)) */
/* sin(dlon * 0.5) = sqrt((pow(sin(dist / R / 2.0), 2) - pow(sin(dlat * 0.5), 2)) / (cos(lat1*DEG_TO_RAD) * cos(lat2*DEG_TO_RAD))) */
/* dlon = (lon2 - lon1) * DEG_TO_RAD = asin(sqrt((pow(sin(dist / R / 2.0), 2) - pow(sin(dlat * 0.5), 2)) / (cos(lat1*DEG_TO_RAD) * cos(lat2*DEG_TO_RAD)))) * 2.0 */
/* lon2 - lon1 = asin(sqrt((pow(sin(dist / R / 2.0), 2) - pow(sin(dlat * 0.5), 2)) / (cos(lat1*DEG_TO_RAD) * cos(lat2*DEG_TO_RAD)))) * 2.0 / DEG_TO_RAD*/
/* lon1 = lon2 - asin(sqrt((pow(sin(dist / R / 2.0), 2) - pow(sin(dlat * 0.5), 2)) / (cos(lat1*DEG_TO_RAD) * cos(lat2*DEG_TO_RAD)))) * 2.0 / DEG_TO_RAD*/
double dlat = (lat2 - lat1) * DEG_TO_RAD;
return lon2 - asin(sqrt((pow(sin(dist / R / 2.0), 2) - pow(sin(dlat * 0.5), 2)) / (cos(lat1*DEG_TO_RAD) * cos(lat2*DEG_TO_RAD)))) * 2.0 * RAD_TO_DEG;
}
int main()
{
double lat1 = 42.34769;
double dist = 1.46628357399041;
double lat2 = 42.367137;
double lon2 = -71.124383;
double lon1 = inverseHaversine_Distance_lon1(lat1, dist, lat2, lon2);
printf("lon1 %f\n", lon1);
printf("dist %f\n", Haversine_Distance(lat1, lon1, lat2, lon2));
}
The result:
gcc inverse_haversine.c -lm
./a.out
lon1 -71.135880
dist 1.466284
It may be possible to reduce the expression...

At least lat1, lat2 and lon2 has to be converted into radians before calling the trigonometric functions! But maybe there are more problems... :)
Example: Using the simple version I got this code i C:
#include <math.h>
#define METERS_PER_DEGREE_EQUATOR 111319.5
#define MILES_PER_DEGREE_EQUATOR (METERS_PER_DEGREE_EQUATOR / 1000.0 / 1.609344)
/* Select preferred unit: */
#define UNITS_PER_DEGREE_EQUATOR MILES_PER_DEGREE_EQUATOR
double horDist(double lat1, double lon1, double lat2, double lon2)
{
/* From "Note on conversion from decimal degrees to meters"
* (http://southport.jpl.nasa.gov/GRFM/cdrom/2a/DOCS/HTML/GEOLOC/METERS.HTM)
* NOTE: BELOW IS ONLY PRECISE IF THE TWO LATITUDES ARE NOT TOO DISTANT! */
double latDelta = UNITS_PER_DEGREE_EQUATOR * (lat1 - lat2);
double lonDelta = UNITS_PER_DEGREE_EQUATOR * (lon1 - lon2) * cos(lat1 * M_PI / 180);
return sqrt(latDelta * latDelta + lonDelta * lonDelta);
}
double invHorDist_lon1(double lat1, double dist, double lat2, double lon2)
{
/* Rewrite horDist wrt lon1: */
/* (dist * dist) = (latDelta * latDelta) + (lonDelta * lonDelta); */
/* (dist * dist) - (latDelta * latDelta) = (lonDelta * lonDelta); */
/* sqrt((dist * dist) - (latDelta * latDelta)) = lonDelta = UNITS_PER_DEGREE_EQUATOR * (lon1 - lon2) * cos(lat1 * M_PI / 180); */
/* sqrt((dist * dist) - (latDelta * latDelta)) / UNITS_PER_DEGREE_EQUATOR / cos(lat1 * M_PI / 180) = (lon1 - lon2); */
double latDelta = UNITS_PER_DEGREE_EQUATOR * (lat1 - lat2);
return sqrt((dist * dist) - (latDelta * latDelta)) / UNITS_PER_DEGREE_EQUATOR / cos(lat1 * M_PI / 180) + lon2;
}
int main()
{
double lon1 = invHorDist_lon1(42.34769, 1.46628357399041, 42.367137, -71.124383);
printf("lon1 %f\n", lon1);
printf("dist %f\n", horDist(42.34769, lon1, 42.367137, -71.124383));
}
And the result is:
gcc haversine.c -lm
./a.out
lon1 -71.112968
dist 1.466284
But again this simple version does not fit if the two latitudes are too distant. But try rewrite Haversine again and convert to radians whenever you use trigonometric functions.

Related

Google Sheets script not recognizing Split function

Here is my code. For some reason Sheets is saying that the "Split function is not recognized".
function distance3(latlon1, latlon2){
var [lat1, lon1] = split(latlon1,",");
var [lat2, lon2] = split(latlon2,",");
var R = 6371000; // radius of the earth in meters, https://en.wikipedia.org/wiki/Earth_radius
var dLat = (lat2-lat1) * Math.PI / 180; // Convert degrees to radians
var dLon = (lon2-lon1) * Math.PI / 180; // Convert degrees to radians
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1 * Math.PI / 180 ) * Math.cos(lat2 * Math.PI / 180 ) *
Math.sin(dLon/2) * Math.sin(dLon/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
// Distance in meters, rounded to an integer.
return Math.round(d)*0.000621371;
}
THANK YOU!
Try:
var [lat1, lon1] = latlon1.split(",");

Add rings to consistent hashing circle to represent data

I am implementing consistent hashing and hence drawing a circle with sectors as shown in the Circle Demo. The sectors represents the Nodes.
The HTML withing which my Circle resides is :
<div id="container1">
<div id="svgcontainer"></div>
</div>
Now I want to add some dots(small rings) over the circumference of the circle to show the key-value pair that belong to a particular node.
I am sing HTML5 for my circle.
After adding the data(key value pair my circle) , the circle should have some rings(or any other representations) on its boundary like required circle output
How can I achieve this in HTML5 ?
TIA :)
The dot for a given sector will be positioned at a point (xd,yd) on the circumference half ways between the sector's (x1,y1) and (x2,y2) points. Calculating the dot's position (xd,yd) will be similar to calculating the sector's (x1,y1) and (x2,y2) but with an angle that is half ways between the anlges used for calculating (x1,y1) and (x2,y2). If you wish to place text near the dot and outside the circle then calculating the text's position (xt,yt) will be similar to calculating the dot's position (xd,yd) but with a larger radius. For example, the existing addSector() function could be modified to...
function addSector() {
sector++;
group.clear();
paper.clear();
var start = 0;
var angle = 360 / sector;
var col = 0;
var x1;
var y1;
var x2;
var y2;
var xd;
var yd;
var xt;
var yt;
var i;
var path;
var dot;
var text;
var textPadding = 15;
for (i = 0; i < sector; i++) {
x1 = Math.round((x + Math.cos(start * Math.PI / 180) * radius) * 100) / 100;
y1 = Math.round((y + Math.sin(start * Math.PI / 180) * radius) * 100) / 100;
x2 = Math.round((x + Math.cos((start + angle) * Math.PI / 180) * radius) * 100) / 100;
y2 = Math.round((y + Math.sin((start + angle) * Math.PI / 180) * radius) * 100) / 100;
path = paper.path("M" + x + "," + y + " L" + x1 + "," + y1 + " A" + radius + "," + radius + " 0 0 1 " + x2 + "," + y2 + "z");
path.attr({"fill": colors[col], "stroke" : null});
group.push(path);
col++;
if (col == colors.length) col = 0;
start += angle;
}
for (i = 0; i < sector; i++) {
start = i * angle;
xd = Math.round((x + Math.cos((start + angle / 2) * Math.PI / 180) * radius) * 100) / 100;
yd = Math.round((y + Math.sin((start + angle / 2) * Math.PI / 180) * radius) * 100) / 100;
dot = paper.circle(xd, yd, 5);
dot.attr({"fill": "#FFFFFF", "stoke": "#000000"});
xt = Math.round((x + Math.cos((start + angle / 2) * Math.PI / 180) * (radius + textPadding)) * 100) / 100;
yt = Math.round((x + Math.sin((start + angle / 2) * Math.PI / 180) * (radius + textPadding)) * 100) / 100;
text = paper.text(xt, yt, i.toString());
}
}

VBA function to calculate Great Circle distances given lat/lon values

I am trying to declare multiple variables in my custom function. Here is what I have so far:
Public Function myDistance(w As Double, x As Double, y As Double, z As Double) As Double
myDistance = Excel.WorksheetFunction.Acos(Cos(radians(90 - w)) * Cos(radians(90 - y))) + Sin(radians(90 - w) * Sin(radians(90 - x)) * Cos(radians(y - z))) * 3958.756
End Function
When I attempt to run the function in my query I get the following error:
Compile Error
Sub or Function Not Defined
My suspicion is the syntax when declaring the variables is incorrect, but I am unsure of how to remedy this. I ran a more simple version of this function without any problem. See below:
Public Function myDistance(x as double) as double
myDistance = Excel.WorksheetFunction.Acos(x)
End Function
The function itself will be used to calculate the distance between two places using latitude and longitude. Do you know how to correct the issue I am having?
Thank you.
This is the function that I use to calculate Great Circle distances, courtesy of
http://www.cpearson.com/excel/LatLong.aspx
Option Compare Database
Option Explicit
' ref: http://www.cpearson.com/excel/LatLong.aspx
Private Const C_RADIUS_EARTH_KM As Double = 6370.97327862
Private Const C_RADIUS_EARTH_MI As Double = 3958.73926185
Private Const C_PI As Double = 3.14159265358979
Function GreatCircleDistance(Latitude1 As Double, Longitude1 As Double, _
Latitude2 As Double, Longitude2 As Double, _
ValuesAsDecimalDegrees As Boolean, _
ResultAsMiles As Boolean) As Double
Dim Lat1 As Double
Dim Lat2 As Double
Dim Long1 As Double
Dim Long2 As Double
Dim X As Long
Dim Delta As Double
If ValuesAsDecimalDegrees = True Then
X = 1
Else
X = 24
End If
' convert to decimal degrees
Lat1 = Latitude1 * X
Long1 = Longitude1 * X
Lat2 = Latitude2 * X
Long2 = Longitude2 * X
' convert to radians: radians = (degrees/180) * PI
Lat1 = (Lat1 / 180) * C_PI
Lat2 = (Lat2 / 180) * C_PI
Long1 = (Long1 / 180) * C_PI
Long2 = (Long2 / 180) * C_PI
' get the central spherical angle
Delta = ((2 * ArcSin(Sqr((Sin((Lat1 - Lat2) / 2) ^ 2) + _
Cos(Lat1) * Cos(Lat2) * (Sin((Long1 - Long2) / 2) ^ 2)))))
If ResultAsMiles = True Then
GreatCircleDistance = Delta * C_RADIUS_EARTH_MI
Else
GreatCircleDistance = Delta * C_RADIUS_EARTH_KM
End If
End Function
Function ArcSin(X As Double) As Double
' VBA doesn't have an ArcSin function. Improvise.
ArcSin = Atn(X / Sqr(-X * X + 1))
End Function

GPS Point to static map Action script

What I am doing wrong? I donot geting numbers trace shows Infinity
function geolocationUpdateHandler(event: GeolocationEvent): void {
event.latitude.toString();
event.longitude.toString();
trace(lat = event.latitude);
trace(lng = event.longitude);
trace(Star.x = (((lng * Math.PI / 180) - (MinLongitude * Math.PI / 180)) / ((MaxLongitude * Math.PI / 180) - (MinLongitude * Math.PI / 180)) / Map.width));
trace(Star.y = (((lat * Math.PI / 180) - (MinLatitude* Math.PI / 180)) / ((MaxLatitude * Math.PI / 180) - (MinLatitude * Math.PI / 180)) / Map.height));
}
var MinLongitude:int;
MinLongitude = 25.139585;
var MaxLongitude:int;
MaxLongitude = 25.332134;
var MaxLatitude:int;
MaxLatitude = 57.790398;
var MinLatitude:int;
MinLatitude = 57.693223;
I'm sure the long/latitudes return as converted to [text] string. No need for .toString method.
Correct way to trace is example: trace("my latitude is.. " + event.location);
In your code try like this:
trace( "lat = " + event.latitude );
trace( "lng = " + event.longitude );
trace( "Star.x = " + (((lng * Math.PI / 180) - (MinLongitude... etc
trace( "Star.y = " + (((lat * Math.PI / 180) - (MinLatitude... etc
Edit:
I just realised you're casting int as the type for your four vars (var MinLongitude:int etc) but also setting them up with fractional inputs. Int's cannot be fractions or have decimal places so change those types to Number eg: (var MinLongitude:Number) etc. Hopefully now you'll get good results.
Otherwise seems there is nothing with your calculation formula. So minus infinity is strange. I did manual calculation...
Star.x = (((lng * Math.PI / 180) - (MinLongitude * Math.PI / 180)) / ((MaxLongitude * Math.PI / 180) - (MinLongitude * Math.PI / 180)) / Map.width));
in calculator becomes: (assume Map.width = 500, Math.PI = 3.14)...
(25.33213 * 3.14 / 180) - (25.139585 * 3.14 / 180) / (25.332134 * 3.14 / 180) - (25.139585 * 3.14 / 180) / 500
and the result 6.077202837190 etc.... so Star.x = 6.0

Type was not found or was not a compile-time constant: Raster

This is the full error message:
C:\Project Files\Good\src\views\RasterView.as(26): col: 39 Error: Type was not found or was not a compile-time constant: Raster.
C:\Project Files\Good\src\views\RasterView.as(42): col: 45 Error: Type was not found or was not a compile-time constant: Raster.
C:\Project Files\Good\src\views\RasterView.as(47): col: 45 Error: Type was not found or was not a compile-time constant: Raster.
C:\Project Files\Good\src\views\RasterView.as(62): col: 32 Error: Type was not found or was not a compile-time constant: Raster.
This is the file(it is huge)
package views
{
import flash.display.Bitmap;
import flash.geom.Point;
import views.Canvas.Raster;
/**
* ...
* #author Arthur Wulf White
*/
public class RasterView extends Bitmap
{
import views.Canvas.Raster
public static const SCHEMATIC : int = 1;
public static const SMOOTH : int = 2;
public static const RENDER_ONCE : int = 4;
public static const BOTH : int = SCHEMATIC + SMOOTH;
// protected var bitmapData : Raster;
protected var viewMode : int = 0;
protected var lineColor : int = 0xff000000;
protected var fillColor : int = 0xff808080;
protected var bgColor : int = 0xffffffff;
public function RasterView(raster : Raster)
{
this.bitmapData = raster;
}
public function getStyle():Vector.<int>
{
return new <int> [lineColor, fillColor, bgColor];
}
public function setStyle(lineColor : int, fillColor : int, bgColor : int):void
{
this.lineColor = lineColor;
this.fillColor = fillColor;
this.bgColor = bgColor;
}
public function backupView(backupRaster : Raster):void
{
backupRaster.copyPixels(bitmapData, bitmapData.rect, new Point());
}
public function loadBackup(backupRaster : Raster):void
{
bitmapData.copyPixels(backupRaster, backupRaster.rect, new Point());
}
public function getViewMode():int
{
return viewMode;
}
public function setViewMode(mode : int):void
{
viewMode = mode;
}
public function get Raster():Raster
{
return Raster(bitmapData);
}
public function refreshView():void
{
bitmapData.lock()
render();
bitmapData.unlock();
if ((getViewMode() & RENDER_ONCE) != 0)
{
setViewMode( getViewMode() ^ RENDER_ONCE);
}
}
public function render():void
{
}
protected function clear():void
{
bitmapData.fillRect(bitmapData.rect, bgColor);
}
}
}
This is the file for the Raster class(I don't think it is important for this issue)
/**
*
* Raster class
*
* #author Didier Brun aka Foxy - www.foxaweb.com
* #version 1.4
* #date 2006-01-06
* #link http://www.foxaweb.com
*
* AUTHORS ******************************************************************************
*
* authorName : Didier Brun - www.foxaweb.com
* contribution : the original class
* date : 2007-01-07
*
* authorName : Drew Cummins - http://blog.generalrelativity.org
* contribution : added bezier curves
* date : 2007-02-13
*
* authorName : Thibault Imbert - http://www.bytearray.org
* contribution : Raster now extends BitmapData, performance optimizations
* date : 2009-10-16
*
* PLEASE CONTRIBUTE ? http://www.bytearray.org/?p=67
*
* DESCRIPTION **************************************************************************
*
* Raster is an AS3 Bitmap drawing library. It provide some functions to draw directly
* into BitmapData instance.
*
* LICENSE ******************************************************************************
*
* This class is under RECIPROCAL PUBLIC LICENSE.
* http://www.opensource.org/licenses/rpl.php
*
* Please, keep this header and the list of all authors
*
*/
package views.Canvas
{
import flash.display.BitmapData;
import flash.display.Shape;
import flash.geom.Point;
import flash.geom.Rectangle;
public class Raster extends BitmapData
{
private var shape : Shape = new Shape();
private var buffer:Array = new Array();
private var r:Rectangle = new Rectangle();
public function Raster ( width:uint, height:uint, transparent:Boolean=false, color:uint=0)
{
super ( width, height, transparent, color);
}
// ------------------------------------------------
//
// ---o public methods
//
// ------------------------------------------------
public function setPoint( p : Point, color : int, size : int = 1):void
{
if(size == 1)
setPixel(p.x, p.y, color);
else if (size > 1)
drawRect(new Rectangle(p.x - size / 2, p.y - size / 2, size, size), color);
}
public function lineAA( x0:int, y0:int, x1:int, y1:int, color:uint ):void
{
var i : int = 0;
var cInt : int;
var cNum : Number;
var div : Number;
var dx : int = Math.abs(x1 - x0);
var dy : int = Math.abs(y1 - y0);
if(dx >= dy)
{
//do x
if (x0 < x1)
{
cInt = x0;
cNum = y0;
}
else
{
cInt = x1;
cNum = y1;
}
div = Number(y1 - y0) / Number(x1 - x0);
setPixel32(cInt, cNum, color);
for (; i <= dx; i++)
{
cInt++;
cNum += div;
setAAPixel(cInt, cNum, color, true, false);
}
}
else
{
//do y
if (y0 < y1)
{
cInt = y0;
cNum = x0;
}
else
{
cInt = y1;
cNum = x1;
}
div = Number(x1 - x0) / Number(y1 - y0);
setPixel32(cNum, cInt, color);
for (; i <= dy; i++)
{
cInt++;
cNum += div;
setAAPixel(cNum, cInt, color, false, true);
}
}
}
public function quadLine(x0 : int, y0 : int, cx : int, cy : int, x1 : int, y1 : int, color : int = 0xff0000ff, detail : int = 20):void
{
var epsilon : Number = 1.0 / Number(detail);
var total : Number = 0;
var x : int = 0;
var y : int = 0;
for (; total <= 1.001; total+=epsilon)
{
x = (1 - total) * ((1 - total) * x0 + total * cx) + total * (total * x1 + (1 - total) * cx);
y = (1 - total) * ((1 - total) * y0 + total * cy) + total * (total * y1 + (1 - total) * cy);
setPixel32(x, y, color);
}
}
/**
* Draws a antialias Quadratic Bezier Curve (equivalent to a DisplayObject's graphics#curveTo)
*
* #param x0 x position of first anchor
* #param y0 y position of first anchor
* #param x1 x position of control point
* #param y1 y position of control point
* #param x2 x position of second anchor
* #param y2 y position of second anchor
* #param c color
* #param resolution [optional] determines the accuracy of the curve's length (higher number = greater accuracy = longer process)
* */
public function aaQuadBezier ( anchorX0:int, anchorY0:int, controlX:int, controlY:int, anchorX1:int, anchorY1:int, c:Number, resolution:int = 3):void
{
shape.graphics.clear();
shape.graphics.lineStyle(1, c, 1);
shape.graphics.moveTo(anchorX0, anchorY0);
shape.graphics.curveTo(controlX, controlY, anchorX1, anchorY1);
this.draw(shape);
}
/**
* Draw an anti-aliased line
*
* #param x0 first point x coord
* #param y0 first point y coord
* #param x1 second point x coord
* #param y1 second point y coord
* #param c color (0xaarrvvbb)
*/
public function aaLine2( x1:int, y1:int, x2:int, y2:int, color:uint ):void
{
shape.graphics.clear();
shape.graphics.lineStyle(1, color, 1);
shape.graphics.moveTo(x1, y1);
shape.graphics.lineTo(x2, y2);
this.draw(shape);
}
/**
* Draw a line
*
* #param x0 first point x coord
* #param y0 first point y coord
* #param x1 second point x coord
* #param y1 second point y coord
* #param c color (0xaarrvvbb)
*/
public function line ( x0:int, y0:int, x1:int, y1:int, color:uint ):void
{
var dx:int;
var dy:int;
var i:int;
var xinc:int;
var yinc:int;
var cumul:int;
var x:int;
var y:int;
x = x0;
y = y0;
dx = x1 - x0;
dy = y1 - y0;
xinc = ( dx > 0 ) ? 1 : -1;
yinc = ( dy > 0 ) ? 1 : -1;
dx = dx < 0 ? -dx : dx;
dy = dy < 0 ? -dy : dy;
setPixel32(x,y,color);
if ( dx > dy )
{
cumul = dx >> 1;
for ( i = 1 ; i <= dx ; ++i )
{
x += xinc;
cumul += dy;
if (cumul >= dx)
{
cumul -= dx;
y += yinc;
}
setPixel32(x,y,color);
}
}else
{
cumul = dy >> 1;
for ( i = 1 ; i <= dy ; ++i )
{
y += yinc;
cumul += dx;
if ( cumul >= dy )
{
cumul -= dy;
x += xinc ;
}
setPixel32(x,y,color);
}
}
}
/**
* Draw a triangle
*
* #param x0 first point x coord
* #param y0 first point y coord
* #param x1 second point x coord
* #param y1 second point y coord
* #param x2 third point x coord
* #param y2 third point y coord
* #param c color (0xaarrvvbb)
*/
public function triangle ( x0:int, y0:int, x1:int, y1:int, x2:int, y2:int, color:uint ):void
{
line (x0,y0,x1,y1,color);
line (x1,y1,x2,y2,color);
line (x2,y2,x0,y0,color);
}
/**
* Draw a filled triangle
*
* #param x0 first point x coord
* #param y0 first point y coord
* #param x1 second point x coord
* #param y1 second point y coord
* #param x2 third point x coord
* #param y2 third point y coord
* #param c color (0xaarrvvbb)
*/
public function filledTri ( x0:int, y0:int, x1:int, y1:int, x2:int, y2:int, color:uint ):void
{
buffer.length = 0;
lineTri (buffer,x0,y0,x1,y1,color);
lineTri (buffer,x1,y1,x2,y2,color);
lineTri (buffer,x2,y2,x0,y0,color);
}
/**
* Draw a circle
*
* #param px first point x coord
* #param py first point y coord
* #param r radius
* #param c color (0xaarrvvbb)
*/
public function circle ( px:int, py:int, r:int, color:uint ):void
{
var x:int;
var y:int;
var d:int;
x = 0;
y = r;
d = 1-r;
setPixel32(px+x,py+y,color);
setPixel32(px+x,py-y,color);
setPixel32(px-y,py+x,color);
setPixel32(px+y,py+x,color);
while ( y > x )
{
if ( d < 0 )
{
d += (x+3) << 1;
}else
{
d += ((x - y) << 1) + 5;
y--;
}
x++;
setPixel32(px+x,py+y,color);
setPixel32(px-x,py+y,color);
setPixel32(px+x,py-y,color);
setPixel32(px-x,py-y,color);
setPixel32(px-y,py+x,color);
setPixel32(px-y,py-x,color);
setPixel32(px+y,py-x,color);
setPixel32(px+y,py+x,color);
}
}
/**
* Draw an anti-aliased circle
*
* #param px first point x coord
* #param py first point y coord
* #param r radius
* #param c color (0xaarrvvbb)
*/
public function aaCircle ( px:int, py:int, r:int, color:uint ):void
{
var vx:int;
var vy:int;
var d:int;
vx = r;
vy = 0;
var t:Number=0;
var dry:Number;
var buff:int;
setPixel(px+vx,py+vy,color);
setPixel(px-vx,py+vy,color);
setPixel(px+vy,py+vx,color);
setPixel(px+vy,py-vx,color);
while ( vx > vy+1 )
{
vy++;
buff = Math.sqrt(r*r-vy*vy)+1;
dry = buff - Math.sqrt(r*r-vy*vy);
if (dry<t) vx--;
drawAlphaPixel(px+vx,py+vy,1-dry,color)
drawAlphaPixel(px+vx-1,py+vy,dry,color)
drawAlphaPixel(px-vx,py+vy,1-dry,color)
drawAlphaPixel(px-vx+1,py+vy,dry,color)
drawAlphaPixel(px+vx,py-vy,1-dry,color)
drawAlphaPixel(px+vx-1,py-vy,dry,color)
drawAlphaPixel(px-vx,py-vy,1-dry,color)
drawAlphaPixel(px-vx+1,py-vy,dry,color)
drawAlphaPixel(px+vy,py+vx,1-dry,color)
drawAlphaPixel(px+vy,py+vx-1,dry,color)
drawAlphaPixel(px-vy,py+vx,1-dry,color)
drawAlphaPixel(px-vy,py+vx-1,dry,color)
drawAlphaPixel(px+vy,py-vx,1-dry,color)
drawAlphaPixel(px+vy,py-vx+1,dry,color)
drawAlphaPixel(px-vy,py-vx,1-dry,color)
drawAlphaPixel(px-vy,py-vx+1,dry,color)
t=dry;
}
}
/**
* Draw an anti-aliased line
*
* #param x0 first point x coord
* #param y0 first point y coord
* #param x1 second point x coord
* #param y1 second point y coord
* #param c color (0xaarrvvbb)
*/
public function aaLine ( x1:int, y1:int, x2:int, y2:int, color:uint ):void
{
var steep:Boolean = Math.abs(y2 - y1) > Math.abs(x2 - x1);
var swap:int;
if (steep)
{
swap=x1; x1=y1; y1=swap;
swap=x2; x2=y2; y2=swap;
}
if (x1 > x2)
{
swap=x1; x1=x2; x2=swap;
swap=y1; y1=y2; y2=swap;
}
var dx:int = x2 - x1;
var dy:int = y2 - y1
var gradient:Number = dy / dx;
var xend:int = x1;
var yend:Number = y1 + gradient * (xend - x1);
var xgap:Number = 1-((x1 + 0.5)%1);
var xpx1:int = xend;
var ypx1:int = yend;
var alpha:Number;
alpha = ((yend)%1) * xgap;
var intery:Number = yend + gradient;
xend = x2;
yend = y2 + gradient * (xend - x2)
xgap = (x2 + 0.5)%1;
var xpx2:int = xend;
var ypx2:int = yend;
alpha = (1-((yend)%1)) * xgap;
if (steep)
drawAlphaPixel(ypx2,xpx2,alpha,color);
else drawAlphaPixel(xpx2, ypx2,alpha,color);
alpha = ((yend)%1) * xgap;
if (steep)
drawAlphaPixel(ypx2 + 1,xpx2,alpha,color);
else drawAlphaPixel(xpx2, ypx2 + 1,alpha,color);
var x:int=xpx1;
while (x++<xpx2)
{
alpha = 1-((intery)%1);
if (steep)
drawAlphaPixel(intery,x,alpha,color);
else drawAlphaPixel(x,intery,alpha,color);
alpha=intery%1;
if (steep)
drawAlphaPixel(intery+1,x,alpha,color);
else drawAlphaPixel(x,intery+1,alpha,color);
intery = intery + gradient
}
}
/**
* Draws a Rectangle
*
* #param rect Rectangle dimensions
* #param color color
* */
public function drawRect ( rect:Rectangle, color:uint ):void
{
line ( rect.x, rect.y, rect.x+rect.width, rect.y, color );
line ( rect.x+rect.width, rect.y, rect.x+rect.width, rect.y+rect.height, color );
line ( rect.x+rect.width, rect.y+rect.height, rect.x, rect.y+rect.height, color );
line ( rect.x, rect.y+rect.height, rect.x, rect.y, color );
}
/**
* Draws a rounded Rectangle
*
* #param rect Rectangle dimensions
* #param ellipseWidth Rectangle corners width
* #param color color
* */
public function drawRoundRect ( rect:Rectangle, ellipseWidth:int, color:uint ):void
{
var arc:Number = 4/3 * (Math.sqrt(2) - 1);
var xc:Number = rect.x+rect.width-ellipseWidth;
var yc:Number = rect.y+ellipseWidth;
line( rect.x+ellipseWidth, rect.y, xc, rect.y, color );
cubicBezier(xc, rect.y, xc + ellipseWidth*arc, yc - ellipseWidth, xc + ellipseWidth, yc - ellipseWidth*arc, xc + ellipseWidth, yc, color);
xc = rect.x+rect.width-ellipseWidth;
yc = rect.y+rect.height-ellipseWidth;
line( xc + ellipseWidth, rect.y+ellipseWidth, rect.x+rect.width, yc, color );
cubicBezier(rect.x+rect.width, yc, xc + ellipseWidth, yc + ellipseWidth*arc, xc + ellipseWidth*arc, yc + ellipseWidth, xc, yc + ellipseWidth, color);
xc = rect.x+ellipseWidth;
yc = rect.y+rect.height-ellipseWidth;
line( rect.x+rect.width-ellipseWidth, rect.y+rect.height, xc, yc + ellipseWidth, color );
cubicBezier( xc, yc + ellipseWidth, xc - ellipseWidth*arc, yc + ellipseWidth, xc - ellipseWidth, yc + ellipseWidth*arc, xc - ellipseWidth, yc, color );
xc = rect.x+ellipseWidth;
yc = rect.y+ellipseWidth;
line( xc - ellipseWidth, rect.y+rect.height-ellipseWidth, rect.x, yc, color );
cubicBezier(rect.x, yc, xc - ellipseWidth, yc - ellipseWidth*arc, xc - ellipseWidth*arc, yc - ellipseWidth, xc, yc - ellipseWidth, color);
}
/**
* Draws a Quadratic Bezier Curve (equivalent to a DisplayObject's graphics#curveTo)
*
* #param x0 x position of first anchor
* #param y0 y position of first anchor
* #param x1 x position of control point
* #param y1 y position of control point
* #param x2 x position of second anchor
* #param y2 y position of second anchor
* #param c color
* #param resolution [optional] determines the accuracy of the curve's length (higher number = greater accuracy = longer process)
* */
public function quadBezier ( anchorX0:int, anchorY0:int, controlX:int, controlY:int, anchorX1:int, anchorY1:int, c:Number, resolution:int = 3):void
{
var ox:Number = anchorX0;
var oy:Number = anchorY0;
var px:int;
var py:int;
var dist:Number = 0;
var inverse:Number = 1 / resolution;
var interval:Number;
var intervalSq:Number;
var diff:Number;
var diffSq:Number;
var i:int = 0;
while( ++i <= resolution )
{
interval = inverse * i;
intervalSq = interval * interval;
diff = 1 - interval;
diffSq = diff * diff;
px = diffSq * anchorX0 + 2 * interval * diff * controlX + intervalSq * anchorX1;
py = diffSq * anchorY0 + 2 * interval * diff * controlY + intervalSq * anchorY1;
dist += Math.sqrt( ( px - ox ) * ( px - ox ) + ( py - oy ) * ( py - oy ) );
ox = px;
oy = py;
}
//approximates the length of the curve
var curveLength:int = dist;
inverse = 1 / curveLength;
var lastx:int=anchorX0;
var lasty:int=anchorY0;
i = -1;
while( ++i <= curveLength )
{
interval = inverse * i;
intervalSq = interval * interval;
diff = 1 - interval;
diffSq = diff * diff;
px = diffSq * anchorX0 + 2 * interval * diff * controlX + intervalSq * anchorX1;
py = diffSq * anchorY0 + 2 * interval * diff * controlY + intervalSq * anchorY1;
line(lastx,lasty,px,py,c);
//aaLine(lastx, lasty, px, py, c);
lastx = px;
lasty = py;
}
}
/**
* Draws a Cubic Bezier Curve
*
* TODO: Determine whether x/y params would be better named as anchor/control
*
* #param x0 x position of first anchor
* #param y0 y position of first anchor
* #param x1 x position of control point
* #param y1 y position of control point
* #param x2 x position of second control point
* #param y2 y position of second control point
* #param x3 x position of second anchor
* #param y3 y position of second anchor
* #param c color
* #param resolution [optional] determines the accuracy of the curve's length (higher number = greater accuracy = longer process)
* */
public function cubicBezier ( x0:int, y0:int, x1:int, y1:int, x2:int, y2:int, x3:int, y3:int, c:Number, resolution:int = 5 ):void
{
var ox:Number = x0;
var oy:Number = y0;
var px:int;
var py:int;
var dist:Number = 0;
var inverse:Number = 1 / resolution;
var interval:Number;
var intervalSq:Number;
var intervalCu:Number;
var diff:Number;
var diffSq:Number;
var diffCu:Number;
var i:int = 0;
while( ++i <= resolution )
{
interval = inverse * i;
intervalSq = interval * interval;
intervalCu = intervalSq * interval;
diff = 1 - interval;
diffSq = diff * diff;
diffCu = diffSq * diff;
px = diffCu * x0 + 3 * interval * diffSq * x1 + 3 * x2 * intervalSq * diff + x3 * intervalCu;
py = diffCu * y0 + 3 * interval * diffSq * y1 + 3 * y2 * intervalSq * diff + y3 * intervalCu;
dist += Math.sqrt( ( px - ox ) * ( px - ox ) + ( py - oy ) * ( py - oy ) );
ox = px;
oy = py;
}
//approximates the length of the curve
var curveLength:int = dist;
inverse = 1 / curveLength;
var lastx:int=x0;
var lasty:int=y0;
i = -1;
while( ++i <= curveLength )
{
interval = inverse * i;
intervalSq = interval * interval;
intervalCu = intervalSq * interval;
diff = 1 - interval;
diffSq = diff * diff;
diffCu = diffSq * diff;
px = diffCu * x0 + 3 * interval * diffSq * x1 + 3 * x2 * intervalSq * diff + x3 * intervalCu;
py = diffCu * y0 + 3 * interval * diffSq * y1 + 3 * y2 * intervalSq * diff + y3 * intervalCu;
line(lastx,lasty,px,py,c);
lastx = px;
lasty = py;
}
}
// ------------------------------------------------
//
// ---o private static methods
//
// ------------------------------------------------
/**
* Draw an AA pixel
*/
private function setAAPixel (x:Number, y:Number, c:Number, roundX : Boolean = false, roundY : Boolean = false):void
{
var xpos : Number = Math.floor(x);
var ypos : Number = Math.floor(y);
var xA : Number = x - xpos;
var yA : Number = y - ypos;
if (!roundX && !roundY)
{
drawAlphaPixel(xpos , ypos , (1 - xA) * (1 - yA) , c);
drawAlphaPixel(xpos + 1 , ypos , xA * (1 - yA) , c);
drawAlphaPixel(xpos , ypos + 1 , (1 - xA) * yA , c);
drawAlphaPixel(xpos + 1 , ypos + 1 , xA * yA , c);
}
else if (roundX && !roundY)
{
drawAlphaPixel(xpos , ypos , (1 - yA) , c);
drawAlphaPixel(xpos , ypos + 1 , yA , c);
}
else if (roundY && !roundX)
{
drawAlphaPixel(xpos , ypos , (1 - xA) , c);
drawAlphaPixel(xpos + 1 , ypos , xA , c);
}
else if (roundX && roundY)
{
setPixel32(xpos , ypos , c);
}
}
/**
* Draw an alpha32 pixel
*/
private function drawAlphaPixel ( x:int, y:int, a:Number, c:Number, bg : int = -1 ):void
{
//var g:uint = getPixel32(x,y);
var g : int = 0xff000000;
var r0:uint = ((g & 0x00FF0000) >> 16);
var g0:uint = ((g & 0x0000FF00) >> 8);
var b0:uint = ((g & 0x000000FF));
var r1:uint = ((c & 0x00FF0000) >> 16);
var g1:uint = ((c & 0x0000FF00) >> 8);
var b1:uint = ((c & 0x000000FF));
var ac:Number = 0xFF;
var rc:Number = r1*a+r0*(1-a);
var gc:Number = g1*a+g0*(1-a);
var bc:Number = b1*a+b0*(1-a);
var n:uint = (ac<<24)+(rc<<16)+(gc<<8)+bc;
setPixel32(x,y,n);
}
/**
* Check a triangle line
*/
private function checkLine ( o:Array, x:int, y:int, c:int, r:Rectangle ):void
{
if (o[y])
{
if (o[y]>x)
{
r.width=o[y]-x;
r.x=x;
r.y=y;
fillRect(r,c);
}else
{
r.width=x-o[y];
r.x=o[y];
r.y=y;
fillRect(r,c);
}
}else
{
o[y]=x;
}
}
/**
* Special line for filled triangle
*/
private function lineTri ( o:Array, x0:int, y0:int, x1:int, y1:int, c:Number ):void
{
var steep:Boolean= (y1-y0)*(y1-y0) > (x1-x0)*(x1-x0);
var swap:int;
if (steep)
{
swap=x0; x0=y0; y0=swap;
swap=x1; x1=y1; y1=swap;
}
if (x0>x1)
{
x0^=x1; x1^=x0; x0^=x1;
y0^=y1; y1^=y0; y0^=y1;
}
var deltax:int = x1 - x0
var deltay:int = (y1 - y0) < 0 ? -(y1 - y0) : (y1 - y0);
var error:int = 0;
var y:int = y0;
var ystep:int = y0<y1 ? 1 : -1;
var x:int = x0;
var xend:int = x1-(deltax>>1);
var fx:int = x1;
var fy:int = y1;
var px:int = 0;
r.x = 0;
r.y = 0;
r.width = 0;
r.height = 1;
while (x++<=xend)
{
if (steep)
{
checkLine(o,y,x,c,r);
if (fx != x1 && fx != xend)
checkLine(o,fy,fx+1,c,r);
}
error += deltay;
if ((error<<1) >= deltax)
{
if (!steep)
{
checkLine(o,x-px+1,y,c,r);
if (fx!=xend)
checkLine(o,fx+1,fy,c,r);
}
px = 0;
y += ystep;
fy -= ystep;
error -= deltax;
}
px++;
fx--;
}
if (!steep)
checkLine(o,x-px+1,y,c,r);
}
}
}
Looks like just a typo or copy/paste error. The import statement should not be repeated inside your class definition:
package views
{
import flash.display.Bitmap;
import flash.geom.Point;
import views.Canvas.Raster; // Yes
/**
* ...
* #author Arthur Wulf White
*/
public class RasterView extends Bitmap
{
import views.Canvas.Raster // No
Also, avoid having an accessor with the same name as a class:
public function get Raster():Raster // Call this function get MyRaster or similar
{
return Raster(bitmapData);
}
Code highlighting is your friend. Any time a property or function name other than your constructor lights up in Cyan, it means you're using an existing class name, which may cause problems.