mirror of https://github.com/kivy/kivy.git
commit
80bc8931c0
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
|
@ -0,0 +1,24 @@
|
|||
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
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
title=Compass
|
||||
author=Nik Klever
|
||||
orientation=portrait
|
|
@ -0,0 +1,223 @@
|
|||
import kivy
|
||||
kivy.require('1.3.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
|
||||
|
||||
Logger.info('COMPASS: STARTED')
|
||||
|
||||
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 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):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""
|
||||
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):
|
||||
"""
|
||||
Building all together:
|
||||
|
||||
1) Creating the parent widget and clearing it to white background color
|
||||
|
||||
2) Defining a suitable position and size of the CompassWidget, the
|
||||
needleSize and the stopButtonHeight depending on the densityDpi value
|
||||
given by DisplayMetrics
|
||||
|
||||
3) Creating an instance of the CompassWidget and adding it to the
|
||||
parent widget and calling the appropriate build function
|
||||
|
||||
4) Creating an instance of the NeedleWidget and adding it also to the
|
||||
parent widget and calling the appropriate build function
|
||||
|
||||
5) Creating an instance of a Button widget and adding it as stopButton
|
||||
also to the parent widget and bind it with the stopApp function
|
||||
|
||||
6) Calling the instance method changeStatus of the magneticFieldSensor
|
||||
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()
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
1323529642.46
|
Loading…
Reference in New Issue