example: rework compass example to work with python-for-android, and remove all broken code.

This commit is contained in:
Mathieu Virbel 2013-06-25 13:56:47 +02:00
parent 509f42cc91
commit 0ec55c7e1d
7 changed files with 76 additions and 230 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

View File

@ -1,24 +0,0 @@
Compass
=======
Demonstrate the combination of the Android Magnetic Field Sensor and the Kivy functionality viewing a Compass.
Kivy Python-For-Android
-----------------------
Please look at the lastest docs of the
`Kivy Python-For-Android Project <http://python-for-android.readthedocs.org/en/latest/>`__
Building an APK
---------------
::
./distribute.sh -m "pyjnius kivy"
::
./build.py --package org.test.compass --name compass \
--version 1.0 --dir ~/code/kivy/examples/android/compass debug

View File

@ -0,0 +1,25 @@
#:kivy 1.7.0
FloatLayout:
canvas:
Color:
rgb: .98, .98, .98
Rectangle:
size: self.size
Image:
source: 'rose.png'
Image:
source: 'needle.png'
canvas.before:
PushMatrix
Rotate:
angle: app.needle_angle
axis: 0, 0, 1
origin: self.center
canvas.after:
PopMatrix

View File

@ -1,223 +1,69 @@
'''
Compass example
===============
This example is a demonstration of Hardware class usage.
But it has severals drawbacks, like using only the magnetic sensor, and
extrapolating values to get the orientation. The compass is absolutely not
accurate.
The right way would be to get the accelerometer + magnetic, and computer
everything according to the phone orientation. This is not the purpose of this
example right now.
You can compile it with::
./build.py --package org.test.compass --name compass \
--private ~/code/kivy/examples/android/compass \
--window --version 1.0 debug installd
'''
import kivy import kivy
kivy.require('1.3.0') kivy.require('1.7.0')
import math
import time
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
from kivy.uix.scatter import Scatter
from kivy.clock import Clock
from kivy.vector import Vector
from kivy.core.window import Window
from kivy.graphics import Color, Ellipse, Rectangle, Triangle
from kivy.logger import Logger
from jnius import autoclass from jnius import autoclass
from kivy.app import App
from kivy.properties import NumericProperty
from kivy.clock import Clock
from kivy.vector import Vector
from kivy.animation import Animation
Logger.info('COMPASS: STARTED') Hardware = autoclass('org.renpy.android.Hardware')
def LoggerDisplayMetrics(metrics):
"""
Logging all values of the Java Android DisplayMetrics class
to get some more information about the metrics of Android devices
"""
display = {'Default':metrics.DENSITY_DEFAULT,
'Device':metrics.DENSITY_DEVICE,
'High':metrics.DENSITY_HIGH,
'Low':metrics.DENSITY_LOW,
'Medium':metrics.DENSITY_MEDIUM,
'XHIGH':metrics.DENSITY_XHIGH,
'density':metrics.density,
'densityDpi':metrics.densityDpi,
'heightPixels':metrics.heightPixels,
'scaledDensity':metrics.scaledDensity,
'widthPixels':metrics.widthPixels,
'xdpi':metrics.xdpi,
'ydpi':metrics.ydpi}
for (k,v) in list(display.items()):
Logger.info('COMPASS: display %s = %s'%(k,v))
class CompassWidget(FloatLayout):
def __init__(self, **kwargs):
"""
Constructor of the CompassWidget class
"""
super(CompassWidget, self).__init__(**kwargs)
def build(self,pos,size):
"""
building the background of the CompassWidget with a circle of a
compass windrose image
(Source of this image: Wikipedia - http://en.wikipedia.org/wiki/Compass_rose)
"""
with self.canvas:
self.pos = pos
self.size = size
self.windrose = Ellipse(source="500px-Windrose.svg.png", pos=pos, size=size)
class NeedleWidget(Scatter):
def __init__(self, **kwargs):
"""
Constructor of the NeedleWidget class
do_rotation, do_translation, do_scale are all set to False
to indicate that the scatter widget can onlybe updated from the
app and not by an interaction with your fingers
"""
super(NeedleWidget, self).__init__(**kwargs)
self.do_rotation = False
self.do_translation = False
self.do_scale = False
self.auto_bring_to_front = True
def rotateNeedle(self,angle):
"""
rotate the NeedleWidget with the parameter angle
90 is subtracted because North of the windrose is at 90 degrees
of the device
"""
self.rotation = angle - 90
def build(self,center,needleSize):
"""
building the needle with two Triangles of different color
"""
self.pos = center - needleSize/2.
self.size = needleSize
self.size_hint = [None, None]
with self.canvas:
Color(1., 0, 0)
needleTP1 = Vector(needleSize[0]/2.,needleSize[1])
needleTP2 = Vector(needleSize[0]/2.,0)
needleTP3 = Vector(-needleSize[0],needleSize[1]/2.)
needlePoints = (needleTP1[0],needleTP1[1],
needleTP2[0],needleTP2[1],
needleTP3[0],needleTP3[1])
self.needleT1 = Triangle(points=needlePoints)
Color(0.5, 0.5, 0.5)
needleTP3 = Vector(2*needleSize[0],needleSize[1]/2.)
needlePoints = (needleTP1[0],needleTP1[1],
needleTP2[0],needleTP2[1],
needleTP3[0],needleTP3[1])
self.needleT2 = Triangle(points=needlePoints)
class CompassApp(App): class CompassApp(App):
def __init__(self, **kwargs): needle_angle = NumericProperty(0)
"""
Constructor of the Compass App
1) The Java Android API DisplayMetrics is called to get
information about the densityDpi factor of the Android device
2) The Kivy Python-For-Android Android API is called to
get access to the hardware sensors of the Android device
"""
super(CompassApp, self).__init__(**kwargs)
DisplayMetrics = autoclass('android.util.DisplayMetrics')
metrics = DisplayMetrics()
metrics.setToDefaults()
LoggerDisplayMetrics(metrics)
self.densityDpi = metrics.densityDpi
Hardware = autoclass('org.renpy.android.Hardware')
self.hw = Hardware()
Logger.info('COMPASS: Hardware Objects: %s'%(str(dir(self.hw))))
Logger.info('COMPASS: Hardware Sensors\n%s\n'%(self.hw.getHardwareSensors()))
def viewCompass(self, *largs):
"""
viewCompass calls the readSensor method of the
magneticFieldSensor instance of the generic3AxisSensor, it reads the
3-tuple value of the magnetic field
the declination angle is computed as the angle of the magnetic field
vector in the x,y-plane and the unity-vector of the y-axis.
afterwards the rotateNeedle function rotates the needle as given
by the declination angle parameter
"""
(x, y, z) = self.hw.magneticFieldSensor.readSensor()
declination = Vector(x,y).angle((0,1))
#Logger.info('COMPASS: viewCompass x=%s y=%s z=%s declination=%s'%(x,y,z,declination))
self.needle.rotateNeedle(declination)
def stopApp(self,*largs):
"""
this function is called when pushed the stopButton, disables
the magneticFieldSensor and stops the app
"""
self.hw.magneticFieldSensor.changeStatus(False)
Logger.info('COMPASS: stop largs '+str(largs))
self.stop()
def build(self): def build(self):
""" self._anim = None
Building all together: Hardware.magneticFieldSensorEnable(True)
Clock.schedule_interval(self.update_compass, 1 / 10.)
1) Creating the parent widget and clearing it to white background color def update_compass(self, *args):
# read the magnetic sensor from the Hardware class
(x, y, z) = Hardware.magneticFieldSensorReading()
2) Defining a suitable position and size of the CompassWidget, the # calculate the angle
needleSize and the stopButtonHeight depending on the densityDpi value needle_angle = Vector(x , y).angle((0, 1)) + 90.
given by DisplayMetrics
3) Creating an instance of the CompassWidget and adding it to the # animate the needle
parent widget and calling the appropriate build function if self._anim:
self._anim.stop(self)
self._anim = Animation(needle_angle=needle_angle, d=.2, t='out_quad')
self._anim.start(self)
4) Creating an instance of the NeedleWidget and adding it also to the def on_pause(self):
parent widget and calling the appropriate build function # when you are going on pause, don't forget to stop the sensor
Hardware.magneticFieldSensorEnable(False)
return True
5) Creating an instance of a Button widget and adding it as stopButton def on_resume(self):
also to the parent widget and bind it with the stopApp function # reactivate the sensor when you are back to the app
Hardware.magneticFieldSensorEnable(True)
6) Calling the instance method changeStatus of the magneticFieldSensor if __name__ == '__main__':
instance with parameter True to enable the magnetic field sensor
and additionally calling the function schedule_interval of the Clock
class for a repeated call of the function viewCompass every second.
"""
parent = FloatLayout(size=(500,500))
Window.clearcolor = (1, 1, 1, 1)
if self.densityDpi == 240:
CompassPos = Vector(50., 200.)
CompassSize = Vector(400., 400.)
needleSize = Vector(100., 60.)
stopButtonHeight = 60
elif self.densityDpi == 320:
CompassPos = Vector(75., 300.)
CompassSize = Vector(600., 600.)
needleSize = Vector(150., 90.)
stopButtonHeight = 90
else:
Logger.info('COMPASS: widget size should be adopted - minimum used for densityDpi=%s'%(str(self.densityDpi)))
CompassPos = Vector(50., 200.)
CompassSize = Vector(400., 400.)
needleSize = Vector(100., 60.)
stopButtonHeight = 60
self.Compass = CompassWidget()
parent.add_widget(self.Compass)
self.Compass.build(pos=CompassPos,size=CompassSize)
self.needle = NeedleWidget()
parent.add_widget(self.needle)
self.needle.build(center=CompassPos+CompassSize/2.,needleSize=needleSize)
self.stopButton = Button(text='Stop', pos_hint={'right':1}, size_hint=(None,None), height=stopButtonHeight)
parent.add_widget(self.stopButton)
self.stopButton.bind(on_press=self.stopApp)
self.hw.magneticFieldSensor.changeStatus(True)
Clock.schedule_interval(self.viewCompass, 1.)
return parent
if __name__ in ('__main__', '__android__'):
CompassApp().run() CompassApp().run()

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -1 +0,0 @@
1323529642.46

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB