Using MonoTouch.CoreText to draw multi-line text - ios

I used that examples
http://developer.xamarin.com/recipes/ios/graphics_and_drawing/core_text/draw_unicode_text_with_coretext/
Using MonoTouch.CoreText to draw text fragments at specific coordinaates
to draw a text line over UIView.
Now I need to extend it to draw multi-line text. Basically is simple. In the Draw() method I split the multi-line string Text on "\n" and than I call DrawTextLine() for any single line adding a newLineDY to Y.
The only problem is that any new line draw starts after the X draw end of the previous one:
aaa
bbb
ccc
How to avoid the X displacement? Can be reset? How? I try appling a negative DX for any line, but I don't know the right value to apply.
private const float newLineDY = 40;
public override void Draw()
{
string[] lines = Text.Split("\n".ToCharArray());
float lx = X;
float ly = Y;
foreach (string line in lines)
{
DrawTextLine(line, lx, ly);
//lx -= 100; // negative DX
ly += newLineDY;
}
}
private void DrawTextLine(string text, float x, float y)
{
CGContext gctx = UIGraphics.GetCurrentContext();
gctx.SaveState();
gctx.TranslateCTM(x, y);
//gctx.TextPosition = new CGPoint(x, y);
gctx.ScaleCTM(1, -1);
//gctx.RotateCTM((float)Math.PI * 315 / 180);
gctx.SetFillColor(UIColor.Black.CGColor);
var attributedString = new NSAttributedString(text,
new CTStringAttributes
{
ForegroundColorFromContext = true,
Font = new CTFont("Arial", 24)
});
using (CTLine textLine = new CTLine(attributedString))
{
textLine.Draw(gctx);
}
gctx.RestoreState();
}
Thaks!

I have solved using attributedString.DrawString(new CGPoint(x, y)), a much simpler API, as suggested here
http://monotouch.2284126.n4.nabble.com/Using-MonoTouch-CoreText-to-draw-text-fragments-at-specific-coordinates-td4658531.html
So my code became:
private const float newLineDY = 40;
public override void Draw()
{
string[] lines = Text.Split("\n".ToCharArray());
float lx = X;
float ly = Y;
foreach (string line in lines)
{
DrawTextLine(line, lx, ly);
ly += newLineDY;
}
}
private void DrawTextLine(string text, float x, float y)
{
NSAttributedString attributedString = new NSAttributedString(
text,
new CTStringAttributes
{
ForegroundColorFromContext = true,
Font = new CTFont("Arial", 24)
});
attributedString.DrawString(new CGPoint(x, y));
}

Related

Calculate distance between parameters and target image

How can I calculate distance between a fixed parameter and a target image/pixel?
The following code does color recognition, finds the average position, and draws circle on it. It is able to find if the target (averageX and averageY) is close to leftPd, centerPd, or rightPd. I want to change this code as lane tracking which is at least able to find distance value between leftPd parameter variable and left lane or rightPd parameter variable and right lane.
import processing.video.*;
Capture video;
float threshold = 210;
color trackColor;
PVector leftP, centerP, rightP, target;
void setup() {
leftP = new PVector (80,420);
centerP = new PVector (width/2, 380);
rightP = new PVector (560,420);
size(640, 480);
video = new Capture(this, width, height);
video.start();
trackColor = color(160,0,0); // Start off tracking for red
}
void captureEvent(Capture video) {
// Read image from the camera
video.read();
}
void draw() {
loadPixels();
video.loadPixels();
image(video, 0, 0);
float avgX = 0;
float avgY = 0;
int count = 0;
for (int x = 0; x < video.width; x ++ ) {
for (int y = 0; y < video.height; y ++ ) {
int loc = x + y*video.width;
color currentColor = video.pixels[loc];
float r1 = red(currentColor);
float g1 = green(currentColor);
float b1 = blue(currentColor);
float r2 = red(trackColor);
float g2 = green(trackColor);
float b2 = blue(trackColor);
// Using euclidean distance to compare colors
float d = distSq(r1, g1, b1, r2, g2, b2);
if (d < threshold) {
stroke(255);
strokeWeight(1);
point(x,y);
avgX += x;
avgY += y;
count++;
}
}
}
if (count > 0) {
avgX = avgX / count;
avgY = avgY / count;
// Draw a circle at the tracked pixel
fill(trackColor);
strokeWeight(4.0);
stroke(0);
ellipse(avgX, avgY, 20, 20);
text("brightnesslevel: " + trackColor, 20, 60);
text("FPS: " + frameRate, 20, 80);
}
target = new PVector (avgX, avgY);
color c = color(255, 204, 0);
fill(c);
noStroke();
ellipse(leftP.x,leftP.y,16,16); // left param
ellipse(centerP.x,centerP.y,16,16); // center param
ellipse(rightP.x,rightP.y,16,16); // right param
float leftPd = leftP.dist(target);
float centerPd = centerP.dist(target);
float rightPd = rightP.dist(target);
if ( leftPd <= 85 ){
text("To Close left " , 20, 250);
}
if ( centerPd <= 85 ){
text("To Close turn center " , 20, 275);
}
if ( rightPd <= 85 ){
text("To Close turn right " , 20, 300);
}
}
float distSq(float x1,float y1, float z1, float x2, float y2, float z2){
float d = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1);
return d;
}
void mousePressed() {
// Save color where the mouse is clicked in trackColor variable
int loc = mouseX + mouseY*video.width;
trackColor = video.pixels[loc];
}

Image printing with Epson compatible Thermal printer problem

I am using C# and write code for print contents for the Thermal ticket printer.
There are codes that people use for image print, and it indeed prints images, but something goes wrong. This is my code for image print class, it is widely using open source (I googled and found it, and people successfully implement this code to theirs without problem).
public static class ImagePrint
{
/// <summary>
/// Image convert to Byte Array
/// </summary>
/// <param name="LogoPath">Image Path</param>
/// <param name="printWidth">Image print Horizontal Length</param>
/// <returns></returns>
public static byte[] GetLogo(string LogoPath, int printWidth)
{
List<byte> byteList = new List<byte>();
if (!File.Exists(LogoPath))
return null;
BitmapData data = GetBitmapData(LogoPath, printWidth);
BitArray dots = data.Dots;
byte[] width = BitConverter.GetBytes(data.Width);
int offset = 0;
// Initialize Printer
byteList.Add(Convert.ToByte(Convert.ToChar(0x1B)));
byteList.Add(Convert.ToByte('#'));
// Line Spacing Adjust (24/180 inch)
byteList.Add(Convert.ToByte(Convert.ToChar(0x1B)));
byteList.Add(Convert.ToByte('3'));
byteList.Add((byte)24);
while (offset < data.Height)
{
byteList.Add(Convert.ToByte(Convert.ToChar(0x1B)));
byteList.Add(Convert.ToByte('*'));
byteList.Add((byte)33);
byteList.Add(width[0]);
byteList.Add(width[1]);
for (int x = 0; x < data.Width; ++x)
{
for (int k = 0; k < 3; ++k)
{
byte slice = 0;
for (int b = 0; b < 8; ++b)
{
int y = (((offset / 8) + k) * 8) + b;
int i = (y * data.Width) + x;
bool v = false;
if (i < dots.Length)
v = dots[i];
slice |= (byte)((v ? 1 : 0) << (7 - b));
}
byteList.Add(slice);
}
}
offset += 24;
byteList.Add(Convert.ToByte(0x0A));
}
// Return to normal line spacing (30/160 inch)
byteList.Add(Convert.ToByte(0x1B));
byteList.Add(Convert.ToByte('3'));
byteList.Add((byte)30);
return byteList.ToArray();
}
private static BitmapData GetBitmapData(string bmpFileName, int width)
{
using (var bitmap = (Bitmap)Bitmap.FromFile(bmpFileName))
{
var threshold = 127;
var index = 0;
double multiplier = width; // 이미지 width조정
double scale = (double)(multiplier / (double)bitmap.Width);
int xheight = (int)(bitmap.Height * scale);
int xwidth = (int)(bitmap.Width * scale);
var dimensions = xwidth * xheight;
var dots = new BitArray(dimensions);
for (var y = 0; y < xheight; y++)
{
for (var x = 0; x < xwidth; x++)
{
var _x = (int)(x / scale);
var _y = (int)(y / scale);
var color = bitmap.GetPixel(_x, _y);
var luminance = (int)(color.R * 0.3 + color.G * 0.59 + color.B * 0.11);
dots[index] = (luminance < threshold);
index++;
}
}
return new BitmapData()
{
Dots = dots,
Height = (int)(bitmap.Height * scale),
Width = (int)(bitmap.Width * scale)
};
}
}
private class BitmapData
{
public BitArray Dots
{
get;
set;
}
public int Height
{
get;
set;
}
public int Width
{
get;
set;
}
}
}
And I use this code like this on my code for image print:
string Image_File_Path = #"D:\TEST\TESTImage.bmp";
int Image_Size_I_Want = 100;
byte[] img = ImagePrint.GetLogo(Image_File_Path, Image_Size_I_Want);
port.Write(img, 0, img.Length);
You can see the result in the attached picture.
There are white space lines on the image.
This class automatically adds a line spacing command, but it seems does not work.
Please suggest any solution.
Using 'mike42/escpos-php' package in laravel
use Mike42\Escpos\Printer;
use Mike42\Escpos\EscposImage;
$tux = EscposImage::load(public_path()."\assets\img\path-to-file.jpg");
$printer->setJustification(Printer::JUSTIFY_CENTER);
$printer->bitImage($tux, 0);
$printer -> setJustification();

Processing save() Function Saves Only Final Result

Here's my code...
void setup() {
size(500, 500);
surface.setResizable(true);
smooth();
dot = loadImage("1-DOT.png");
}
void draw() {
background(255);
grid(dot, 5, .2);
}
void grid(PImage img, int dim, float scale) {
int imgsize = floor(img.width * scale);
int canvassize;
for (int i = 1; i <= dim; i++) {
canvassize = dim * imgsize;
surface.setSize(canvassize, canvassize);
for (int x = 0; x < canvassize; x += imgsize) {
for (int y = 0; y < canvassize; y += imgsize) {
image(img, x, y, imgsize, imgsize);
}
}
save("grid_" + str(i) + ".png");
}
}
The grid function takes an image file, a dimension parameter, and a scale. It creates square grids of sizes 0 to dim from image.
It should save each iteration of this grid as a file. But it doesn't. What I am left with once I run the code is (in this case), 5 identical 5x5 grids. I should have a 1x1 grid, a 2x2 grid and so on. I have also attempted to use saveFrame(), but to no avail.
Thanks in advance!
Majlik is correct that you aren't calculating your canvassize correctly. If you want it to be different each iteration of the loop, then you need to use i instead of dim.
But on top of that, it seems like a really bad idea to change the size of your surface in the middle of a call to draw(). That throws an IndexOutOfBoundsException for me.
Instead, you'll probably have better luck if you create a PGraphics of whatever size you want and draw to that. Here's an example:
void setup() {
PImage dot = loadImage("dot.png");
grid(dot, 5, .2);
exit();
}
void grid(PImage img, int dim, float scale) {
int imgsize = floor(img.width * scale);
for (int i = 1; i <= dim; i++) {
int canvassize = i * imgsize;
PGraphics pg = createGraphics(canvassize, canvassize);
pg.beginDraw();
for (int x = 0; x < canvassize; x += imgsize) {
for (int y = 0; y < canvassize; y += imgsize) {
pg.image(img, x, y, imgsize, imgsize);
}
}
pg.endDraw();
pg.save("grid_" + str(i) + ".png");
}
}
That creates these images:
Also, notice that I'm not calling this from the draw() function: your program would continuously create images, which is not necessary. Just create them once and then exit.
I think you have mistake on calculating a canvassize. If I get your goal right you should use i instead of dim.
canvassize = i * imgsize; // Corrected
Also it is easier to use saveFrame instead of save
saveFrame("grid_###.png");
But I tested in only with Java Mode (without surface methods).

How to change color of image in JavaFX

I have a PNG image like this:
I want to change image to something like this:
How can I do this in JavaFX?
As you don't care if it is a vector shape or a bitmap, I'll just outline solutions using a bitmap here. If you actually wanted a vector shape, I believe you would need to work with vector input to get a good result.
Use a ColorAdjust effect with the brightness set to minimum (-1).
Cache the result for SPEED.
Here is a sample which creates a shadow outline of an image:
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.effect.ColorAdjust;
import javafx.scene.image.*;
import javafx.stage.Stage;
public class Shadow extends Application {
#Override
public void start(Stage stage) throws Exception {
ImageView imageView = new ImageView(
new Image(
"http://i.stack.imgur.com/jbT1H.png"
)
);
ColorAdjust blackout = new ColorAdjust();
blackout.setBrightness(-1.0);
imageView.setEffect(blackout);
imageView.setCache(true);
imageView.setCacheHint(CacheHint.SPEED);
stage.setScene(new Scene(new Group(imageView)));
stage.show();
}
public static void main(String[] args) {
Application.launch();
}
}
Here is another sample which adjusts the color of an image, hover over smurfette to make her blush.
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.scene.*;
import javafx.scene.effect.*;
import javafx.scene.image.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class Shadow extends Application {
#Override
public void start(Stage stage) throws Exception {
Image image = new Image(
"http://icons.iconarchive.com/icons/designbolts/smurfs-movie/128/smurfette-icon.png"
);
ImageView imageView = new ImageView(image);
imageView.setClip(new ImageView(image));
ColorAdjust monochrome = new ColorAdjust();
monochrome.setSaturation(-1.0);
Blend blush = new Blend(
BlendMode.MULTIPLY,
monochrome,
new ColorInput(
0,
0,
imageView.getImage().getWidth(),
imageView.getImage().getHeight(),
Color.RED
)
);
imageView.effectProperty().bind(
Bindings
.when(imageView.hoverProperty())
.then((Effect) blush)
.otherwise((Effect) null)
);
imageView.setCache(true);
imageView.setCacheHint(CacheHint.SPEED);
stage.setScene(new Scene(new Group(imageView), Color.AQUA));
stage.show();
}
public static void main(String[] args) {
Application.launch();
}
}
The below code will replace one pixel color with another. If you run that multiple times over your original image replacing gray scale values with color values you should be set.
To save memory you might want to adapt the code to reuse the writeable image for each loop.
/**
* reColor the given InputImage to the given color
* inspired by https://stackoverflow.com/a/12945629/1497139
* #param inputImage
* #param oldColor
* #param newColor
* #return reColored Image
*
*/
public static Image reColor(Image inputImage, Color oldColor, Color newColor) {
int W = (int) inputImage.getWidth();
int H = (int) inputImage.getHeight();
WritableImage outputImage = new WritableImage(W, H);
PixelReader reader = inputImage.getPixelReader();
PixelWriter writer = outputImage.getPixelWriter();
int ob=(int) oldColor.getBlue()*255;
int or=(int) oldColor.getRed()*255;
int og=(int) oldColor.getGreen()*255;
int nb=(int) newColor.getBlue()*255;
int nr=(int) newColor.getRed()*255;
int ng=(int) newColor.getGreen()*255;
for (int y = 0; y < H; y++) {
for (int x = 0; x < W; x++) {
int argb = reader.getArgb(x, y);
int a = (argb >> 24) & 0xFF;
int r = (argb >> 16) & 0xFF;
int g = (argb >> 8) & 0xFF;
int b = argb & 0xFF;
if (g==og && r==or && b==ob) {
r=nr;
g=ng;
b=nb;
}
argb = (a << 24) | (r << 16) | (g << 8) | b;
writer.setArgb(x, y, argb);
}
}
return outputImage;
}
I tried Wolfgang's reColor method above, but when I was trying to just recolor an image where I was trying to change all white pixels to another color, the result was always off and in many cases it wouldn't replace the colors at all, defaulting them to flat black for a variety of different colors that I tried.
So after figuring out what his code was doing, I came up with this method that actually does a one-for-one color pixel replacement and it works quite well.
import javafx.scene.paint.Color;
import javafx.scene.image.*;
private static Image reColor(Image inputImage, Color sourceColor, Color finalColor) {
int W = (int) inputImage.getWidth();
int H = (int) inputImage.getHeight();
WritableImage outputImage = new WritableImage(W, H);
PixelReader reader = inputImage.getPixelReader();
PixelWriter writer = outputImage.getPixelWriter();
float ocR = (float) sourceColor.getRed();
float ocG = (float) sourceColor.getGreen();
float ocB = (float) sourceColor.getBlue();
float ncR = (float) finalColor.getRed();
float ncG = (float) finalColor.getGreen();
float ncB = (float) finalColor.getBlue();
java.awt.Color oldColor = new java.awt.Color(ocR, ocG, ocB);
java.awt.Color newColor = new java.awt.Color(ncR, ncG, ncB);
for (int y = 0; y < H; y++) {
for (int x = 0; x < W; x++) {
int argb = reader.getArgb(x, y);
java.awt.Color pixelColor = new java.awt.Color(argb, true);
writer.setArgb(x, y,
pixelColor.equals(oldColor) ?
newColor.getRGB() :
pixelColor.getRGB());
}
}
return outputImage;
}

How to translate a given coordinate into a bounding box of "diameter" x?

For example, I have a latitude and longitude in decimal format (as opposed to Degrees-Hours-Minutes like lat=44.1° 9.5' 30''). To search for nearby objects, I must specify the search "radius" as a rectangle with four values:
north = 44.1;
south = -9.9;
east = -22.4;
west = 55.2;
Is there a formula or rule of thumb how to convert decimal lat/long values into a rectangular bounding box, such that the given latitude/longitude is in the center of that box?
Must I fiddle around myself with a WGS84 ellipsoid algorithm or are there open solutions to the problem?
I had exactly this problem and the solution isn't that straight forward, but the good news is that after a lot of work (and a great deal of help from SO and Google) I think I've cracked it.
There are lots of libraries around such as Proj4 which offer a multitude of algorithms to perform the required transformations, but coming at it cold I found it all a bit confusing and ended up writing my own code (I always like to know how things work).
My solution is based on ECEF and it works like this...
As I'm sure you've figured out, lines of latitude are always the same distance apart (the distance between 10 degrees and 20 degrees is the same as that between 20 and 30), but lines of longitude converge to meet at the poles. So the distance between 10 degrees and 20 degrees longitude at the equator is much larger than near the poles (and is 0 at the poles).
So you can easily work out how many metres between 2 degrees of latitude, but to do this with longitude you have to take the latitude into account.
Near the equator 1 degree of lat is pretty much the same distance as 1 degree of long, so if the map we're projecting had it's centre (0, 0) we can simply multiply lat and long by a constant to get metres from the map centre for any given point.
So my algorithm effectively rotates the globe until the actual centre of the map is at 0, 0.
So say the centre is really at (50.52, -4.82) - which it is in my case.
Imagine you're holding a globe and looking down on it with 0 lat, 0 long directly below you in the visible centre.
What we need to do is take our globe which currently has (0, 0) directly below us and rotate it in a westward (to the right) direction until (0, -4.82) is below us.
Then we rotate the globe southward (down) until (50.52, -4.82) is below us.
As a third step, we may then want to rotate it clockwise or anti-clockwise to correct for the orientation of the map with respect to true north (if true north is straight up on your map or if all you are interested in is distance not bearing, you won't need to do this)
So conceptually that's what we need to do, but how does that relate to our algorithm?
The answer is a transform (class) where we feed in three angles of rotation. This class has a public function which, given a lat/long pair, will return a new lat/long pair of that point on the globe after rotation.
And once we've done that, knowing the radius of the earth, we can convert this new pair into x and y coordinates, representing the distance from our map origin.
I should mention here that the earth is wider at the equator than it is at the poles, but the maths to deal with this is quite simply not worth the bother. However you calculate your x, y coords they will always be slightly out since the earth is not flat and for me, the code presented below does the job.
If your map is very close to the poles I suspect the results from this algorith may become quite inaccurate - basically lat/long doesn't really work very well at the poles (just take a look at google earth from above).
The MapTransform class requires you to setup a few things.
setRadius(1000); sets up the transform to work with a sphere of radius 1000 (units)
setBody("EARTH"); sets up the transform with the mean radius of the earth (in metres)
setRotation(x, y, z); sets up the transform to rotate about Z axis by z degrees, Y axis by y degrees then X axis by x degrees.
- basically, given your centre point (lat, long) and given that true north on the map is straight up, you would need the following: setRotation(0, lat, -long);
- the order of rotation is very important here and based on a coordinate system (looking back at the globe you're holding) where the Z axis coincides with the rotation of the earth, the Y axis rotates the closest surface of the globe up/down and the X axis is the axis you are looking along - hope this makes sense, it's a difficult concept to describe - see Rotation Matrix
Given your requirement to map from lat/long to metres from a specific point, the above should be all you need.
The function getMapPosition(lat, long) will return a double[] containing x, y in map units (metres if radius was specified in metres) from your origin
My class goes a bit further in terms of applying the coordinates to a specific map tile...
setMapOrigin(x, y); sets up where the rotational origin of the map (the point directly below the observer after rotation) is in relation to the bottom left corner of your map. Nominally this should be in metres (certainly if you used setBody("EARTH");) but needs to be in the same units as the specified radius.
setMapSize(w, h); sets up the size of the map in metres or what ever units you decided to use.
Finally, setBitmapSize(w, h) allows you to describe the size of the bitmap (in pixels) onto which you are projecting your map. In my application I have a bitmap representation of the map area and use the transform to supply the exact coorinates of the pixel on my bitmap where a point should be plotted. However, this isn't part of the question you asked so you may not need it.
Really hope this helps - seems just as long winded and complicated as all the examples I was looking at a month ago now.
import java.text.DecimalFormat;
public class MapTransform {
private double circumference;
private RotationMatrix rotationMatrix;
private double originX;
private double originY;
private double mapWidth;
private double mapHeight;
private int bitmapWidth;
private int bitmapHeight;
public MapTransform() {
this.circumference = 0;
this.rotationMatrix = new RotationMatrix();
this.rotationMatrix.makeIdentity();
this.originX = 0;
this.originY = 0;
this.mapWidth = 0;
this.mapHeight = 0;
this.bitmapWidth = 0;
this.bitmapHeight = 0;
}
public void setCircumference(double circumference) {
this.circumference = circumference;
}
public void setRadius(double radius) {
this.circumference = 2 * Math.PI * radius;
}
public void setBody(String body) {
if (body.toUpperCase().equals("EARTH")) {
setRadius(6371009); //mean radius of the earth in metres
// setRadius(6378137); //equatorial radius of the earth in metres
// setRadius(6356752); //polar radius of the earth in metres
}
else {
setRadius(0);
}
}
public void setRotation(double xRotateDegrees, double yRotateDegrees, double zRotateDegrees) {
RotationMatrix xMatrix = new RotationMatrix();
RotationMatrix yMatrix = new RotationMatrix();
RotationMatrix zMatrix = new RotationMatrix();
xMatrix.makeRotateX(Math.toRadians(xRotateDegrees));
yMatrix.makeRotateY(Math.toRadians(yRotateDegrees));
zMatrix.makeRotateZ(Math.toRadians(zRotateDegrees));
this.rotationMatrix = zMatrix.concatenate(yMatrix).concatenate(xMatrix);
}
public void setMapOrigin(double originX, double originY) {
this.originX = originX;
this.originY = originY;
}
public void setMapSize(double width, double height) {
this.mapWidth = width;
this.mapHeight = height;
}
public void setBitmapSize(int width, int height) {
this.bitmapWidth = width;
this.bitmapHeight = height;
}
public double[] getMapPosition(double[] geoPosition) {
return getMapPosition(geoPosition[0], geoPosition[1]);
}
public double[] getMapPosition(double latitude, double longitude) {
// convert the GeoPosition into an NVector
NVector vec = new NVector(latitude, longitude);
// rotate the vector in 3D
vec = rotationMatrix.transform(vec);
// convert the vector into 2D units by applying circumference to latitude/longitude and adding origins
double x = vec.getLongitude() * this.circumference / 360;
double y = vec.getLatitude() * this.circumference / 360;
// return a MapPosition
return new double[] {x, y};
}
public float[] getPixelPosition(double[] mapPosition) {
return getPixelPosition(mapPosition[0], mapPosition[1]);
}
public float[] getPixelPosition(double mapX, double mapY) {
// apply origin and scale based on map and bitmap widths
float x = (float) ((this.originX + mapX) * this.bitmapWidth / this.mapWidth);
// apply origin and scale based on map and bitmap heights, but invert to measure from top left instead of bottom left
float y = (float) (this.bitmapHeight - (this.originY + mapY) * this.bitmapHeight / this.mapHeight);
return new float[] {x, y};
}
public class RotationMatrix {
String name = "";
public double array [][] = {{0,0,0},{0,0,0},{0,0,0}};
public RotationMatrix() {}
public RotationMatrix(String name) {
this.name = name;
}
public void makeIdentity() {
for(int x = 0; x <= 2; x++) {
for (int y = 0; y <= 2; y++) {
array[x][y] = (x == y)? 1: 0;
}
}
}
public void makeRotateX(double thetaRadians) {
double cosTheta = Math.cos(thetaRadians);
double sinTheta = Math.sin(thetaRadians);
makeIdentity();
array[1][1] = cosTheta;
array[2][1] = -sinTheta;
array[1][2] = sinTheta;
array[2][2] = cosTheta;
}
public void makeRotateY(double thetaRadians) {
double cosTheta = Math.cos(thetaRadians);
double sinTheta = Math.sin(thetaRadians);
makeIdentity();
array[0][0] = cosTheta;
array[2][0] = sinTheta;
array[0][2] = -sinTheta;
array[2][2] = cosTheta;
}
public void makeRotateZ(double thetaRadians) {
double cosTheta = Math.cos(thetaRadians);
double sinTheta = Math.sin(thetaRadians);
makeIdentity();
array[0][0] = cosTheta;
array[1][0] = -sinTheta;
array[0][1] = sinTheta;
array[1][1] = cosTheta;
}
public NVector transform(NVector vec) {
NVector vec2 = new NVector();
vec2.x = vec.x * array[0][0] + vec.y * array[1][0] + vec.z * array[2][0];
vec2.y = vec.x * array[0][1] + vec.y * array[1][1] + vec.z * array[2][1];
vec2.z = vec.x * array[0][2] + vec.y * array[1][2] + vec.z * array[2][2];
return vec2;
}
public void output() {
if (this.name != null && this.name.length() == 0) {
System.out.println(this.name + "-------");
}
DecimalFormat df = new DecimalFormat("0.00");
for(int y = 0; y <= 2; y++) {
String out = "| ";
double test = 0;
for(int x = 0; x <= 2; x++) {
String f = df.format(array[x][y]);
if (f.length() < 5) f = " " + f;
out += f + " ";
test = test + array[x][y] * array[x][y];
}
if (test > 0.99 && test < 1.01) {test = 1.0;}
out += "| (=" + test + ")";
System.out.println(out);
}
System.out.println();
}
public RotationMatrix concatenate(RotationMatrix m2) {
RotationMatrix outputMatrix = new RotationMatrix();
for(int x = 0; x <= 2; x++) {
for(int y = 0; y <=2; y++) {
outputMatrix.array[x][y] = 0;
for (int q = 0; q <= 2; q++) {
outputMatrix.array[x][y] += this.array[x][q] * m2.array[q][y];
}
}
}
return outputMatrix;
}
}
public class NVector {
double x;
double y;
double z;
public NVector() {
this.x = 0;
this.y = 0;
this.z = 0;
}
public NVector(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
public NVector(double latitude, double longitude) {
setLatitudeLongitude(latitude, longitude);
}
public NVector(double[] geoPosition) {
setLatitudeLongitude(geoPosition[0], geoPosition[1]);
}
private void setLatitudeLongitude(double latitude, double longitude) {
double latitudeRadians = Math.toRadians(latitude);
double longitudeRadians = Math.toRadians(longitude);
double cosLatitude = Math.cos(latitudeRadians);
double cosLongitude = Math.cos(longitudeRadians);
double sinLatitude = Math.sin(latitudeRadians);
double sinLongitude = Math.sin(longitudeRadians);
this.x = cosLatitude * cosLongitude;
this.y = cosLatitude * sinLongitude;
this.z = sinLatitude;
}
public double getLatitude() {
return Math.toDegrees(Math.atan2(this.z, Math.sqrt(this.x * this.x + this.y * this.y)));
}
public double getLongitude() {
return Math.toDegrees(Math.atan2(this.y, this.x));
}
public double[] getGeoPosition() {
double[] geoPosition = new double[] {this.getLatitude(), this.getLongitude()};
return geoPosition;
}
public void output() {
output("");
}
public void output(String name) {
if (name != null && name.length() == 0) {
System.out.println("NVector: " + name);
}
DecimalFormat df = new DecimalFormat("0.00");
String vector = df.format(this.x) + "," + df.format(this.y) + "," + df.format(this.z);
String coords = "";
try {
coords = df.format(Math.toDegrees(this.getLatitude())) + "N " + df.format(Math.toDegrees(this.getLongitude())) + "E";
}
catch(Exception e) {
coords = "(coords unknown)";
}
System.out.println("(" + vector + ") at " + coords);
}
}
}
If you're talking about coordinates on a globe, isn't there really no clear definition of "rectangular bounding box" on a manifold?
Couldn't you just approximate the center of the "box" by averaging the dimensions of the rectagle as in cartesian coordinates:
x_center = x_left + (x_right - x_left) / 2
y_center = y_bottom + (y_top - y_bottom) / 2
Why not do a range/bearing from your center point to define the lat/lon's of the corner of the box (if that is what you are asking)? Use the four bearings 45 deg, 135 deg, 225 deg, 315 deg. See this web site for "Destination point from range/bearing": http://www.movable-type.co.uk/scripts/latlong.html
Another, much shorter answer to my other post if you just need the distance to another lat long from your point of origin which I found on SO (surprise).
Original answer was here, but I believe the code you're looking for is...
public static double distFrom(double lat1, double lng1, double lat2, double lng2) {
double earthRadius = 6371009; //mean radius of the earth in metres
double dLat = Math.toRadians(lat2-lat1);
double dLng = Math.toRadians(lng2-lng1);
double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
Math.sin(dLng/2) * Math.sin(dLng/2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
double dist = earthRadius * c;
return dist;
}

Resources