【问题描述】
用户在指定的停车场里停车时,能够对自己停放车辆的位置进行拍照记录,然后再取车时可以利用本软件进行拍照定位。本软件的定位全部依赖于停车场中到处部署的二维码,用户可以随时用手机拍照并获得自己的位置。本软件还能够自动提示用户停车的计费情况等信息。
【基本要求】
一个完整的系统应具有以下功能:
(1)能够对停车场位置信息进行统一管理。对其停车位和停车地点利用二维码拍照来定位查看。即需首先对整个停车场进行建模和二维码生成与标识,对每个停车位都用唯一二维码标记;
(2)用户可以用本软件随时拍身边的二维码,可以在地图上标识出自己的地理位置;
(3)停车时用本软件拍照标记,在回来拿车时,可以根据标记好的位置,用软件来随时拍照定位及拿车路径的导引。
基于Phonegap实现,二维码扫描依赖phonegap插件phonegap-plugin-barcodescanner实现,停车场二维示意图在canvas画布上呈现。
首先对停车场建模,所设计的二维停车场模型形成A、B、C、D4个区域,每个区域16个停车位,即整个停车场共64个车位。每个车位有4位编号,编号用于导航算法使用。第一位为所在区字母,第二位0或1(0表示北方向1表示南方向),第三位0或1(0表示西方向,1表示东方向),最后一位数字1~4,表示距离该区中心位置第几个车位。例如A003,表示距离A区中心位置北偏东方向第三个车位。
将每个停车位编码号利用在线二维码生成平台生成二维码,每个二维码仅存储车位编号。扫描二维码时,获取到车位的编号,根据导航算法进行推算。“停车”扫描传入停车位置的编号,点“扫描二维码”扫描用户当前所在位置停车位的二维码,获取当前停车位的编号。
由编号推到像素坐标过程:保存扫描所识别的编号为字符串,截取编号第一位,判断所在区域,例如A003,就定位到A区像素坐标;判断第二位,0时停车位像素坐标Y=中心点Y值-第三位数值*停车位宽,1时Y=中心点Y值+第三位数值*停车位宽;判断第二位数字,0时停车位像素坐标X=中心点X值-路宽/2,1时X=中心点X值+路宽/2。
导航算法:代码中存有各个区域中心点(十字交叉口位置)的像素坐标,当用户停车时根据停车位编号,推导出车所在停车位的像素坐标,在此扫描二维码获取到当前位置的编号。1、判断两个位置是否在同一个区域,即编号第一位是否相等,不相等执行2,相等执行3;2、以当前位置像素坐标为起点画线,先画到所在区域中心点,先x后y,再由当前所在位置区域的中心位置画到车所在位置区域的中心点,最后由车所在区域中心点画线到车的像素坐标;3、由当前位置像素坐标为起点画线,先y后x,直接画到车的像素坐标。
计时收费:按停车按钮时调用开始计时函数,按导航时停止计时。
图2.1 停车收费流程图
花费时间最多的地方在于二维码扫描的插件的配置,所使用Phonegap版本7.0,安卓版本7.0,尝试过很多方式导入插件,最后发现是打开方式不对,phonegap-plugin-barcodescanner插件由zxing开发而来,当前最稳定的版本是3.0,由于其使用arr文件格式,导入到eclipse中就会出现找不到引用包的情况,使用android-studio导入可以避免。
插件安装过程如2.2。新建phonegap程序,cordova create hello com.example.cordova hellopark,跳转到文件夹内 cd MyBarcode,添加android平台cordova platform add android,利用nodejs添加插件,输入phonegap plugin add phonegap-plugin-barcodescanner。
导入工程,打开android-studio,其中有很多坑,直接导入并不能运行,正确的导入方法是打开F:\hello\platforms\android的build.gradle文件。
图2.2 安装二维码扫描插件
<html>
<head>
<script type="text/javascript" src="cordova.js">script>
<style type="text/css">
canvas{
border: 1px solid #000;
}
.button{
background-color: #C4E3CB; /* Green */
border: none;
padding: 2px 2px;
text-align: center;
font-size: 16px;
margin-right: 20px;
margin-top:18px;
float: left;
width: 80px;
height: 40Spx;
border-radius: 12px;/*圆角*/
}
.button:active {
background-color: #6E828A;
box-shadow: 0 5px #666;
transform: translateY(4px);
border-radius: 12px;/*圆角*/
}
style>
head>
<body>
<center>
<canvas id="canvas" width="304" height="504" >canvas>
<div id="test" style="margin-top:2px;">位置信息div>
<div style="margin-top:2px;">
<span>费用:span><input type="text" id="pay" style="width:50px">
<span>元 (1元/时)span>
div>
<div style="text-align:center; margin-left:55px;margin-top:30px;">
<button class="button" οnclick="timedCount();parking();" >停车button>
<button class="button" οnclick="scannerCode()">扫描二维码button>
<button class="button" οnclick=" search()" >导航button>
div>
<button class="button" οnclick=" re()" style="margin-left:155" >重新定位button>
center>
<script type="text/javascript">
function re(){
location.reload();
}
var canvas,context;var img;//图片对象
var loadImg=function(){//加载图像
canvas=document.getElementById('canvas');
context=canvas.getContext('2d');
img=new Image();
img.οnlοad=function(){
imgIsLoaded=true;
drawImage();
}
img.src="img/1.png";
}();
function drawImage(){
context.clearRect(0,0,canvas.width,canvas.height);
context.drawImage(img,0,0);
}
function timedCount()//开始计时
{
document.getElementById('pay').value=c;
c=c+1/60;
t=setTimeout("timedCount()",1000);
}
function stopCount()//停止计时
{
c=0;
clearTimeout(t);
}
//中心区域坐标
var Ax=77;
var Ay=118;
var Bx=227;
var By=118;
var Cx=78;
var Cy=378;
var Dx=227;
var Dy=378;
var str;
var carA,carX,carY,carAX,carAY;//车的位置
var nowA,nowX,nowY;//当前位置
var x,y;
var c=0,t;//计时
function LocA(str){
var area=str.substring(0,1);
var y=str.substring(1,2);
var x=str.substring(2,3);
var n=str.substring(3,4);
var result = {
area:area,
n: n,
x: x,
y: y
};
return result;
}
function transform(area,x,y,n){//转换为像素坐标
var areaX,areaY;
if (area=="A") {
areaX=Ax;
areaY=Ay;
if (y==0) {
nowY=Ay-(n*25+12.5);
}
else{
nowY=Ay+(n*25+12.5);
}
if (x==0) {
nowX=Ax-25;
}
else{
nowX=Ax+25;
}
}
if (area=="B") {
areaX=Bx;
areaY=By;
if (y==0) {
nowY=By-(n*25+12.5);
}
else{
nowY=By+(n*25+12.5);
}
if (x==0) {
nowX=Bx-25;
}
else{
nowX=Bx+25;
}
}
if (area=="C") {
areaX=Cx;
areaY=Cy;
if (y==0) {
nowY=Cy-(n*25+12.5);
}
else{
nowY=Cy+(n*25+12.5);
}
if (x==0) {
nowX=Cx-25;
}
else{
nowX=Cx+25;
}
}
if (area=="D") {
areaX=Dx;
areaY=Dy;
if (y==0) {
nowY=Dy-(n*25+12.5);
}
else{
nowY=Dy+(n*25+12.5);
}
if (x==0) {
nowX=Dx-25;
}
else{
nowX=Dx+25;
}
};
var result={
areaX:areaX,
areaY:areaY,
x:nowX,
y:nowY
};
return result;
}
function parking(){
//扫码的js接口代码
cordova.plugins.barcodeScanner.scan(
function (result) {
str= result.text;
document.getElementById("test").innerHTML = "您的车位为:" +str;
},
function (error) {
alert("扫描失败: " + error);
});
}
function scannerCode(){
//扫码的js接口代码
cordova.plugins.barcodeScanner.scan(
function (result) {
strNow= result.text;
document.getElementById("test").innerHTML = "您的位置为:" +strNow;
},
function (error) {
alert("扫描失败: " + error);
});
}
function search(){
var imgX,imgY;
carA=LocA(str).area;
var carLoc=transform(LocA(str).area,LocA(str).x,LocA(str).y,LocA(str).n);
carAX=carLoc.areaX;
carAY=carLoc.areaY;
carX=carLoc.x;
carY=carLoc.y;
canvas=document.getElementById('canvas');
context=canvas.getContext('2d');
img=new Image();
img.src="img/car.png";
if (LocA(str).x==0) {
imgX=carX-50;
}
else{
imgX=carX;
}
imgY=carY-12.5;
context.drawImage(img,imgX,imgY);
nowA=LocA(strNow).area;
var nowloc=transform(LocA(strNow).area,LocA(strNow).x,LocA(strNow).y,LocA(strNow).n)
nowX=nowloc.x;
nowY=nowloc.y;
img=new Image();
img.src="img/location.png";
if (LocA(strNow).x==0) {
imgX=nowX-50;
}
else{
imgX=nowX+25;
}
imgY=nowY-12.5;
context.drawImage(img,imgX,imgY);
context.strokeStyle = 'red';
context.lineWidth = 3;
context.moveTo(nowX,nowY);
if (nowA==carA) {ollll
if (nowloc.x==0) {
context.lineTo(nowX+25,nowY);
}
else{
context.lineTo(nowX-25,carY);
context.lineTo(carX,carY);
}
}
else{
context.lineTo(nowloc.areaX,nowY);
context.lineTo(nowloc.areaX,nowloc.areaY);
context.lineTo(nowloc.areaX,carAY);
context.lineTo(carAX,carAY);
context.lineTo(carAX,carY);
context.lineTo(carX,carY);
}
context.stroke();
}
script>
body>
html>
测试用例A003、D113。
图2.3 A003二维码 图2.4 D113二维码
图2.5 app初识界面 图2.6 二维码识别
图2.7 停车后开始计时 图2.8 导航结果