×

Discussion Board

Results 1 to 11 of 11
  1. #1
    Registered User
    Join Date
    Nov 2011
    Posts
    11

    Simple animation problem

    I need some simple animation for my map app(Nutiteq SDK). On map I show user location and around user location I draw "virtual radar". I write it but on touch screen when I am draging map it doesn't paint properly. I think that anim thread isn't sync with UI thread. Anim slow behind draging. And I don't know how to solve this.

    Here is a code for drawing in paint method which draw this "virtual radar":

    Code:
    if (locationSource != null && locationSource.getStatus() == LocationSource.STATUS_CONNECTED) {
    
    if (isGPS) {
    	g.setColor(0xFF0000FF);
    
    	g.drawArc(signalPiksel.getX() - r, signalPiksel.getY() - r, 2 * r, 2 * r, startAngle, angle);
    
    	g.drawArc(signalPiksel.getX() - r + 1, signalPiksel.getY() - r + 1, 2 * (r - 1), 2 * (r - 1), startAngle, angle);
    
    	g.drawArc(signalPiksel.getX() - r + 2, signalPiksel.getY() - r + 2, 2 * (r - 2), 2 * (r - 2), startAngle, angle);
    } else {
    		startTime = 0;
    		r = 0;
    		isGPS = true;
    		repaint();
    		Display.getDisplay(Mapper.instance).callSerially(anim);
    	}
    
    }
    And this is Anim thread:

    Code:
    import javax.microedition.lcdui.Display;
    
    public class Anim extends Thread {
    
    	private int procenat;
    
    	public void run() {
    
    		if (MapScreen.instance.isGPS) {
    
    			if (MapScreen.instance.startTime == 0)
    				MapScreen.instance.startTime = System.currentTimeMillis();
    
    			MapScreen.instance.pixelPos(); // some calculation
    
    			if (MapScreen.instance.r < MapScreen.instance.rKM) {
    				procenat = (int) ((System.currentTimeMillis() - MapScreen.instance.startTime) / 2);
    				MapScreen.instance.r = (procenat * MapScreen.instance.rKM) / 1000;
    			} else {
    				MapScreen.instance.startTime = 0;
    				MapScreen.instance.r = 0;
    			}
    
    			MapScreen.instance.repaint();
    
    			try {
    				Thread.sleep(20);
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    
    			Display.getDisplay(Mapper.instance).callSerially(this);
    
    		}
    
    	}
    
    }
    Almost the same code I use for Android app without callSerially and it works fine. If I don't sleep thread than I almost made dead lock.
    Last edited by noksi; 2011-12-02 at 15:00.

  2. #2
    Nokia Developer Expert
    Join Date
    Aug 2011
    Posts
    555

    Re: Simple animation problem

    I will have to look into that and get back to you.

    In the meantime, you can do something similar with custom markers by using the Nokia Maps API for Java ME, but that would require that you use the Nokia library for displaying Map relevant content. More information about this here:

    Custom Markers code example:
    http://www.developer.nokia.com/Devel...amples/#custom

    Nokia Maps API for Java ME:
    http://www.developer.nokia.com/Devel...I_for_Java_ME/

  3. #3
    Registered User
    Join Date
    Nov 2011
    Posts
    11

    Re: Simple animation problem

    Run the code below to see problem on any touch screen phone when draging map. You must add to res folder gps_marker.png and gps_connection_lost.png App must first locate you than animation will start. And location will be fixed in center of screen in this demo app.

    class Mapper
    Code:
    import javax.microedition.lcdui.Display;
    import javax.microedition.midlet.MIDlet;
    import javax.microedition.midlet.MIDletStateChangeException;
    
    import com.nutiteq.log.Log;
    
    public class Mapper extends MIDlet {
    
    	public static Mapper instance;
    	private MapScreen screen;
    
    	public Mapper() {
    		instance = this;
    	}
    
    	protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
    		screen = null;
    		instance.notifyDestroyed();
    		instance = null;
    	}
    
    	protected void pauseApp() {
    
    	}
    
    	protected void startApp() throws MIDletStateChangeException {
    		Log.enableAll();
    		if (screen == null) {
    			screen = new MapScreen();
    		}
    		Display.getDisplay(this).setCurrent(screen);
    		screen.repaint();
    	}
    }
    class MapScreen
    Code:
    import javax.microedition.lcdui.Canvas;
    import javax.microedition.lcdui.Command;
    import javax.microedition.lcdui.CommandListener;
    import javax.microedition.lcdui.Display;
    import javax.microedition.lcdui.Displayable;
    import javax.microedition.lcdui.Graphics;
    import javax.microedition.midlet.MIDletStateChangeException;
    
    import com.nutiteq.MapComponent;
    import com.nutiteq.components.MapPos;
    import com.nutiteq.components.PlaceIcon;
    import com.nutiteq.components.Point;
    import com.nutiteq.components.WgsPoint;
    import com.nutiteq.controls.MGMapsKeysHandler;
    import com.nutiteq.listeners.MapListener;
    import com.nutiteq.location.LocationListener;
    import com.nutiteq.location.LocationMarker;
    import com.nutiteq.location.LocationSource;
    import com.nutiteq.location.NutiteqLocationMarker;
    import com.nutiteq.location.providers.LocationAPIProvider;
    import com.nutiteq.ui.DefaultCursor;
    import com.nutiteq.utils.Utils;
    
    public class MapScreen extends Canvas implements CommandListener, MapListener {
    
    	public static MapScreen instance;
    
    	private final MapComponent map;
    
    	private final Command exit = new Command("Exit", Command.EXIT, 0);
    	private final Command but1 = new Command("Item1", Command.SCREEN, 1);
    	private final Command but2 = new Command("Item2", Command.SCREEN, 2);
    	private final Command but3 = new Command("Item3", Command.SCREEN, 3);
    	private final Command but4 = new Command("Item4", Command.SCREEN, 4);
    
    	private com.nutiteq.wrappers.Graphics graphicsWrapper;
    
    	private LocationSource locationSource;
    	private LocationMarker marker;
    
    	public double xGPS = 20.466027;
    	public double yGPS = 44.810537;
    	private double xGPSlast = 0.0;
    	private double yGPSlast = 0.0;
    
    	private MapPos signalPiksel = new MapPos(0, 0, 0);
    	private MapPos boundBoxMin;
    	private MapPos boundBoxMax;
    	public long startTime;
    	public int r;
    	public int rKM;
    	private int kurs;
    	private int put;
    	private int startAngle;
    	private int angle;
    
    	private Anim anim;
    
    	public boolean isGPS = false;
    
    	public double range;
    
    	public MapScreen() {
    		instance = this;
    
    		map = new MapComponent(
    				"LICENCE",
    				Mapper.instance, getWidth(), getHeight(), new WgsPoint(xGPS,
    						yGPS), 12);
    
    		MGMapsKeysHandler keyHandler = new MGMapsKeysHandler();
    		map.setControlKeysHandler(keyHandler);
    
    		map.setMapListener(this);
    
    		map.showZoomLevelIndicator(true);
    
    		if (hasPointerEvents()) {
    			setFullScreenMode(false);
    
    			map.setTouchClickTolerance(25);
    			map.showDefaultOnScreenZoomControls();
    		} else {
    			setFullScreenMode(true);
    
    			map.setCursor(new DefaultCursor(0xFFFF0000));
    		}
    
    		map.startMapping();
    
    		range = 1.0; // in KM
    
    		com.nutiteq.wrappers.Image gpsPresentImage = Utils
    				.createImage("/gps_marker.png");
    		com.nutiteq.wrappers.Image gpsConnectionLost = Utils
    				.createImage("/gps_connection_lost.png");
    
    		if (System.getProperty("microedition.location.version") != null) {
    			locationSource = new LocationAPIProvider(1000);
    			marker = new NutiteqLocationMarker(new PlaceIcon(gpsPresentImage),
    					new PlaceIcon(gpsConnectionLost), 1000, true);
    
    			locationSource.setLocationMarker(marker);
    			map.setLocationSource(locationSource);
    
    			locationSource.addLocationListener(new LocationListener() {
    				public void setLocation(WgsPoint p) {
    					xGPSlast = xGPS;
    					yGPSlast = yGPS;
    					xGPS = p.getLon();
    					yGPS = p.getLat();
    
    					kurs = (int) (WgsPoint.initialTrueCourse(new WgsPoint(
    							xGPSlast, yGPSlast), p));
    					put = (int) (WgsPoint.distanceInMeters(new WgsPoint(
    							xGPSlast, yGPSlast), p));
    
    					if (put == 0)
    						angle = 360;
    					else
    						angle = 900 / put;
    
    					if (angle < 72)
    						angle = 72;
    					else if (angle > 360)
    						angle = 360;
    
    					startAngle = 90 - kurs - angle / 2;
    
    					marker.updatePosition();
    				}
    			});
    		}
    
    		anim = new Anim();
    		anim.start();
    
    		addCommand(exit);
    		addCommand(but1);
    		addCommand(but2);
    		addCommand(but3);
    		addCommand(but4);
    		setCommandListener(this);
    
    	}
    
    	protected void paint(Graphics g) {
    		if (graphicsWrapper == null)
    			graphicsWrapper = new com.nutiteq.wrappers.Graphics(g);
    
    		map.paint(graphicsWrapper);
    
    		g.setColor(0, 0, 0);
    
    		if (locationSource != null
    				&& locationSource.getStatus() == LocationSource.STATUS_CONNECTED) {
    			if (isGPS) {
    				g.setColor(0xFF0000FF);
    
    				g.drawArc(signalPiksel.getX() - r, signalPiksel.getY() - r,
    						2 * r, 2 * r, startAngle, angle);
    
    				g.drawArc(signalPiksel.getX() - r + 1, signalPiksel.getY() - r
    						+ 1, 2 * (r - 1), 2 * (r - 1), startAngle, angle);
    
    				g.drawArc(signalPiksel.getX() - r + 2, signalPiksel.getY() - r
    						+ 2, 2 * (r - 2), 2 * (r - 2), startAngle, angle);
    			} else {
    				startTime = 0;
    				r = 0;
    				isGPS = true;
    				repaint();
    				Display.getDisplay(Mapper.instance).callSerially(anim);
    			}
    		} else if (locationSource != null
    				&& locationSource.getStatus() == LocationSource.STATUS_CONNECTING) {
    			g.drawString("Connecting to location...", getWidth(), 0,
    					Graphics.TOP | Graphics.RIGHT);
    			isGPS = false;
    		} else if (locationSource != null
    				&& locationSource.getStatus() == LocationSource.STATUS_CANT_LOCATE) {
    			g.drawString("Can't locate", getWidth(), 0, Graphics.TOP
    					| Graphics.RIGHT);
    			isGPS = false;
    		} else if (locationSource != null
    				&& locationSource.getStatus() == LocationSource.STATUS_CONNECTION_LOST) {
    			g.setColor(0xFFFF0000);
    			g.drawString("Connection lost", getWidth(), 0, Graphics.TOP
    					| Graphics.RIGHT);
    			isGPS = false;
    		}
    
    	}
    
    	public void pixelPos() {
    		signalPiksel = map.getMap().wgsToMapPos(
    				new Point((int) (xGPS * 1000000), (int) (yGPS * 1000000)),
    				map.getZoom());
    		boundBoxMin = map.getMap()
    				.wgsToMapPos(
    						new Point((int) (map.getBoundingBox().getWgsMin()
    								.getLon() * 1000000),
    								(int) (map.getBoundingBox().getWgsMin()
    										.getLat() * 1000000)), map.getZoom());
    		boundBoxMax = map.getMap()
    				.wgsToMapPos(
    						new Point((int) (map.getBoundingBox().getWgsMax()
    								.getLon() * 1000000),
    								(int) (map.getBoundingBox().getWgsMax()
    										.getLat() * 1000000)), map.getZoom());
    
    		signalPiksel.setX(signalPiksel.getX() - boundBoxMin.getX());
    		signalPiksel.setY(signalPiksel.getY() - boundBoxMax.getY());
    
    		switch (map.getZoom()) {
    		case 17:
    			rKM = (int) (range * 1180);
    			break;
    		case 16:
    			rKM = (int) (range * 590);
    			break;
    		case 15:
    			rKM = (int) (range * 295);
    			break;
    		case 14:
    			rKM = (int) (range * 147.5);
    			break;
    		case 13:
    			rKM = (int) (range * 73.75);
    			break;
    		case 12:
    			rKM = (int) (range * 36.875);
    			break;
    		case 11:
    			rKM = (int) (range * 18.4375);
    			break;
    		case 10:
    			rKM = (int) (range * 9.21875);
    			break;
    		default:
    			rKM = 0;
    			break;
    		}
    	}
    
    	protected void keyPressed(final int keyCode) {
    		map.keyPressed(keyCode);
    	}
    
    	protected void keyReleased(final int keyCode) {
    		map.keyReleased(keyCode);
    	}
    
    	protected void keyRepeated(final int keyCode) {
    		map.keyRepeated(keyCode);
    	}
    
    	protected void pointerPressed(int x, int y) {
    		map.pointerPressed(x, y);
    	}
    
    	protected void pointerDragged(int x, int y) {
    		map.pointerDragged(x, y);
    	}
    
    	protected void pointerReleased(int x, int y) {
    		map.pointerReleased(x, y);
    	}
    
    	public void commandAction(Command c, Displayable d) {
    
    		if (c == exit) {
    			map.stopMapping();
    			try {
    				Mapper.instance.destroyApp(true);
    			} catch (final MIDletStateChangeException ignore) {
    			}
    		}
    	}
    
    	public void mapClicked(WgsPoint pnt) {
    	}
    
    	public void mapMoved() {
    	}
    
    	public void needRepaint(boolean downloadReady) {
    		repaint();
    	}
    
    }
    class Anim
    Code:
    
    import javax.microedition.lcdui.Display;
    
    public class Anim extends Thread {
    
    	private int procenat;
    
    	public void run() {
    
    		if (MapScreen.instance.isGPS) {
    
    			if (MapScreen.instance.startTime == 0)
    				MapScreen.instance.startTime = System.currentTimeMillis();
    
    			MapScreen.instance.pixelPos(); // some calculation
    
    			if (MapScreen.instance.r < MapScreen.instance.rKM) {
    				procenat = (int) ((System.currentTimeMillis() - MapScreen.instance.startTime) / 2);
    				MapScreen.instance.r = (procenat * MapScreen.instance.rKM) / 1000;
    			} else {
    				MapScreen.instance.startTime = 0;
    				MapScreen.instance.r = 0;
    			}
    
    			MapScreen.instance.repaint();
    
    			try {
    				Thread.sleep(20);
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    
    			Display.getDisplay(Mapper.instance).callSerially(this);
    
    		}
    
    	}
    
    }
    Last edited by noksi; 2011-12-02 at 16:25.

  4. #4
    Nokia Developer Expert
    Join Date
    Aug 2011
    Posts
    555

    Re: Simple animation problem

    Yes I can see what the problem is. Do you need the virtual radar to be placed always around your current location or do you need to move the virtual radar to the location set by the PointerDragged method?

  5. #5
    Registered User
    Join Date
    Nov 2011
    Posts
    11

    Re: Simple animation problem

    Always around current location and if user drag map then anim need to be draw properly to follow user location which is shown with marker. In this demo app location is fixed in center of screen, but in real app user location can be fixed and unfixed. This anim is same as in Trapster for J2ME. My app is similar to Trapster, users share police location... And this virtual radar is something like searching for police traps which depends from range(this can be set in settings). And when user start moving then only arc will be draw depends of user direction. Only problem is when user drag a map, the rest is fine. Like I said almost the same code work fine on Android...
    Last edited by noksi; 2011-12-05 at 16:06.

  6. #6
    Nokia Developer Expert
    Join Date
    Aug 2011
    Posts
    555

    Re: Simple animation problem

    The problem lies in the way you define your Nutiteq Location Marker object.

    According to the Java Documentation found in Nutiteq's SDK, the NutiteqLocationMarker is defined as follows:

    NutiteqLocationMarker
    public NutiteqLocationMarker(Placemark placemarkConnected,
    Placemark connectionLost,
    int updateInterval,
    boolean track)

    Parameters:
    placemarkConnected - marker for location source connected
    connectionLost - marker for connection to location source lost
    updateInterval - update interval for marker display. If 0, then screen will be updated when location is received from location source
    track - move center of map to received location
    track is a boolean that you set to true if you need to move the center of your map to the received location and false otherwise. Since you have set it to true, the map always centers around your marker when you repaint your canvas.
    You will therefore need to set the track argument to false.

    You need to replace this line:
    Code:
    marker = new NutiteqLocationMarker(new PlaceIcon(gpsPresentImage),
    					new PlaceIcon(gpsConnectionLost), 1000, true);

    with this line:

    Code:
    marker = new NutiteqLocationMarker(new PlaceIcon(gpsPresentImage),
    					new PlaceIcon(gpsConnectionLost), 1000, false);

  7. #7
    Registered User
    Join Date
    Nov 2011
    Posts
    11

    Re: Simple animation problem

    No, that isn't a problem. I set it to true because this demo app will find your location and than will move map to that location. So you can see animation. You can set it to false but drag map to your location and than drag map to see how animation draws. It doesn't draws properly on touch screen phone when you drag map. It doesn't follow dragging. It isn't nice user experience.

  8. #8
    Nokia Developer Expert
    Join Date
    Aug 2011
    Posts
    555

    Re: Simple animation problem

    It doesn't draws properly on touch screen phone when you drag map. It doesn't follow dragging
    I was under the impression your problem was that the center of the screen was being set firmly back to the marker that shows the device's current location and therefore you couldn't drag the screen to the surrounding location. Can you elaborate more on what the problem is?

    If I set the tracker to false, I can drag the screen to other locations and when I return back to my current location I can still see the marker.

    On which device and software version are you testing?

  9. #9
    Registered User
    Join Date
    Nov 2011
    Posts
    11

    Re: Simple animation problem

    I try on few nokia touch screen phone like X6, 5800 and on virtulal machine(Esmertec) on win platform. Like I said animation works like virtual radar and when you don't drag map everything is fine(run the code bellow). When you are dragging map, during dragging animation doesn't draws properly it has delays, it doesn't follow dragging. Animation works in this demo only for zoom from 10 to 17.
    Last edited by noksi; 2011-12-07 at 16:19.

  10. #10
    Registered User
    Join Date
    Nov 2011
    Posts
    11

    Re: Simple animation problem

    pixelPos() must be call from paint method not from Anim thread.

  11. #11
    Nokia Developer Expert
    Join Date
    Aug 2011
    Posts
    555

    Re: Simple animation problem

    That's right,

    The operations in the animation thread are not executed simultaneously with the dragging of the map, that causes calls to paint. If you move the PixelPos method inside the paint method you always get the most recent coordinates just before painting, so you don't experience the delay that you see.

Similar Threads

  1. Animation Problem
    By chirpylife in forum Qt
    Replies: 13
    Last Post: 2010-03-05, 10:59
  2. How to pause simple animation midlet
    By adamj2 in forum Mobile Java General
    Replies: 0
    Last Post: 2008-02-22, 15:12
  3. animation problem
    By Gill in forum Symbian
    Replies: 4
    Last Post: 2007-03-21, 09:15
  4. gif animation problem
    By bojkar in forum Symbian
    Replies: 5
    Last Post: 2007-03-16, 09:04
  5. Replies: 0
    Last Post: 2003-03-19, 12:31

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
×