/*
* XCTrack - XContest Live Tracking client for J2ME devices
* Copyright (C) 2009 Petr Chromec <petr@xcontest.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.xcontest.xctrack.widget;
import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Graphics;
import org.xcontest.xctrack.info.LocationInfoResult;
import org.xcontest.xctrack.paint.GeneralFont;
import org.xcontest.xctrack.paint.TextPainter;
import org.xcontest.xctrack.util.Format;
import org.xcontest.xctrack.widget.settings.DataSourceSettings;
import org.xcontest.xctrack.widget.settings.FlyCompassSettings;
public class FlyCompassWidget extends Widget {
private static final int COLOR_WIND=0xFFFF80;
private static final int COLOR_HEADING=0x6080FF;
private static final int COLOR_HEADING_POINT_OUTER=0xFFFFFF;
private static final int COLOR_HEADING_POINT_INNER=0xC0D0FF;
private static final int COLOR_LETTERS=0xFFFFFF;
private Font _font;
private TextPainter _textPainter;
private int _idxSettings;
private int _idxHeadingSource;
public FlyCompassWidget() {
_font = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_LARGE);
_textPainter = new TextPainter(GeneralFont.NumberFonts,1);
_idxSettings = addSettings(new FlyCompassSettings());
_idxHeadingSource = addSettings(new DataSourceSettings(DataSourceSettings.HEADING));
}
protected int getDefaultHeight() {
return 300;
}
protected int getDefaultWidth() {
return 300;
}
public String getName() {
return "FlyCompass";
}
private static final int getX(int centerX, double angle, double radius) {
return centerX+(int)Math.floor(radius*Math.sin(angle*Math.PI/180));
}
private static final int getY(int centerY, double angle, double radius) {
return centerY-(int)Math.floor(radius*Math.cos(angle*Math.PI/180));
}
private static void paintArrow(Graphics g, int color, int centerx, int centery, double angle, double radius) {
g.setColor(color);
g.fillTriangle(getX(centerx,angle,radius), getY(centery,angle,radius),
getX(centerx,angle+28,radius*0.72), getY(centery,angle+28,radius*0.72),
getX(centerx,angle-28,radius*0.72), getY(centery,angle-28,radius*0.72));
g.fillTriangle(getX(centerx,angle+172,radius), getY(centery,angle+172,radius),
getX(centerx,angle-9,radius*0.72), getY(centery,angle-9,radius*0.72),
getX(centerx,angle+9,radius*0.72), getY(centery,angle+9,radius*0.72));
g.fillTriangle(getX(centerx,angle-9,radius*0.72), getY(centery,angle-9,radius*0.72),
getX(centerx,angle+172,radius), getY(centery,angle+172,radius),
getX(centerx,angle-172,radius), getY(centery,angle-172,radius));
}
protected void paint(Graphics g, Object[] obj) {
FlyCompassSettings.Data s = (FlyCompassSettings.Data)obj[_idxSettings];
DataSourceSettings.Data headingSource = (DataSourceSettings.Data)obj[_idxHeadingSource];
LocationInfoResult loc = WidgetInfo.getLocation();
double heading = WidgetInfo.getHeading(headingSource);
int centerx,centery;
int radius;
int headingPointRadius=0;
int x,y,w,h;
int fonth;
boolean showNESW;
boolean hasRotation;
double rotation;
x = g.getClipX();
y = g.getClipY();
w = g.getClipWidth();
h = g.getClipHeight();
fonth = _font.getHeight();
centerx = x + w/2;
centery = y + h/2;
radius = (w < h ? w : h)/2;
if (s.showLetters == FlyCompassSettings.HIDE)
showNESW = false;
else if (s.showLetters == FlyCompassSettings.SHOW)
showNESW = true;
else
showNESW = radius > 4*fonth;
if (showNESW)
radius -= fonth;
if (s.displayHeadingPoint) {
headingPointRadius = radius/7;
if (headingPointRadius < 5) headingPointRadius = 5;
if (!showNESW)
radius -= headingPointRadius/2;
}
if (s.northAtTop) {
hasRotation = true;
rotation = 0;
}
else {
hasRotation = !Double.isNaN(heading);
rotation = heading;
}
g.setColor(0xffffff);
g.drawArc(centerx-radius, centery-radius, 2*radius-1, 2*radius-1, 0, 360);
if (hasRotation) {
for (int i = 0; i < 360; i += 10) {
int r = i % 30 == 0 ? radius*88/100 : radius*95/100;
g.drawLine(getX(centerx,i-rotation,r), getY(centery,i-rotation,r), getX(centerx,i-rotation,radius), getY(centery,i-rotation,radius));
}
if (showNESW) {
g.setFont(_font);
g.setColor(COLOR_LETTERS);
g.drawString("N",getX(centerx,0-rotation,radius+fonth/2),getY(centery,0-rotation,radius+fonth/2)-fonth/2,Graphics.HCENTER|Graphics.TOP);
g.drawString("E",getX(centerx,90-rotation,radius+fonth/2),getY(centery,90-rotation,radius+fonth/2)-fonth/2,Graphics.HCENTER|Graphics.TOP);
g.drawString("S",getX(centerx,180-rotation,radius+fonth/2),getY(centery,180-rotation,radius+fonth/2)-fonth/2,Graphics.HCENTER|Graphics.TOP);
g.drawString("W",getX(centerx,270-rotation,radius+fonth/2),getY(centery,270-rotation,radius+fonth/2)-fonth/2,Graphics.HCENTER|Graphics.TOP);
}
if (s.displayWind && loc.hasWind) {
paintArrow(g,COLOR_WIND,centerx,centery,loc.windAvgDirection + 180 - rotation,radius);
}
if (!Double.isNaN(heading) && s.displayHeading) {
paintArrow(g,COLOR_HEADING,centerx,centery,heading-rotation,radius);
}
if (s.displayWind && loc.hasWind) {
g.setColor(0);
int r = radius*60/100;
int size = (int)(r/1.3);
g.fillArc(centerx-r, centery-r, 2*r, 2*r, 0, 360);
g.setColor(COLOR_WIND);
_textPainter.paint(g, Format.number(loc.windAvgSpeed, 1), 0, centerx-size, centery-size, 2*size, 2*size, Graphics.HCENTER | Graphics.VCENTER);
}
if (!Double.isNaN(heading) && s.displayHeadingPoint) {
int r = headingPointRadius;
g.setColor(COLOR_HEADING_POINT_OUTER);
g.fillArc(getX(centerx-r,heading-rotation,radius-headingPointRadius/2),
getY(centery-r,heading-rotation,radius-headingPointRadius/2),
r*2, r*2, 0, 360);
int border = r/5;
if (border != 2) border = 2;
r = headingPointRadius-border;
g.setColor(COLOR_HEADING_POINT_INNER);
g.fillArc(getX(centerx-r,heading-rotation,radius-headingPointRadius/2),
getY(centery-r,heading-rotation,radius-headingPointRadius/2),
r*2, r*2, 0, 360);
}
}
}
}