Jack Huang's Blog


  • 首页

  • 标签

  • 归档

  • 搜索

Cesium中飞行器姿态控制

发表于 2018-06-10 | 更新于 2020-11-29

问题提出

最近研究开源虚拟地球Cesium,遇到一个问题:在获取飞行器经度纬度高度偏航俯仰滚转六个参数的前提下,如何在Cesium中用CZML文件表示,从而完美实现飞行器姿态轨迹的复现。在CZML的position属性中使用cartographicDegrees表示飞行器的经度纬度高度,可以很好复现飞行器的轨迹。然而在CZML的orientation属性中使用unitQuaternion表示飞机自身姿态时,飞机姿态总是不对。

问题分析

基本知识

在Cesium中存在两种常用坐标系:

  1. 世界坐标系
    世界坐标系统是以椭球中心为原点的笛卡尔空间直角坐标系。
  2. 地理坐标系
    地理坐标系即人们常用的使用经度、纬度、高度表示位置的坐标系。
  3. 站心坐标系
    又称为Earth-fixed coordinate system(站点坐标系、东-北-天坐标系ENU)。可分为站心直角坐标系和站心极坐标系。
    常用的站心直角坐标系定义为:以站心(如GPS接收天线中心)为坐标系原点O,Z轴与椭球法线重合,向上为正(天向),y与椭球短半轴重合(北向),x轴与地球椭球的长半轴重合(东向)所构成的直角坐标系,称为当地东北天坐标系(ENU)。
    飞行器的偏航、俯仰、滚转即是以站心直角坐标系为参考。
  4. 模型坐标系
    模型坐标系以物体的中心为坐标原点,物体旋转、平移等操作都是围绕局部坐标系进行的。这时当物体模型进行旋转、平移等操作时,局部坐标系也执行相应的旋转、平移等操作。
    局部坐标系是一个假想的坐标系,该坐标系与物体的相对位置至始至终是不变的,假想出这个坐标系的目的主要是为了正向理解对三维场景中物体执行的平移和旋转操作。使用局部坐标系理解模型变换时,所有的变换操作直接作用与局部坐标系,由于局部坐标系与物体的相对位置不变,因此对局部坐标系进行平移、旋转和缩放时,物体在场景中位置和形状也会发生相应的变化。

在Cesium中存在两种世界坐标系和地理坐标系之间坐标转换的方法:

1
2
3
4
5
6
7
8
9
# 经纬度转换为世界坐标
Cesium.Cartesian3.fromDegrees(longitude, latitude, height, ellipsoid, result)
# 世界坐标转换为经纬度
var ellipsoid=viewer.scene.globe.ellipsoid;
var cartesian3=new Cesium.cartesian3(x,y,z);
var cartographic=ellipsoid.cartesianToCartographic(cartesian3);
var lat=Cesium.Math.toDegrees(cartograhphic.latitude);
var lng=Cesium.Math.toDegrees(cartograhpinc.longitude);
var alt=cartographic.height;

CZML分析

CZML是一种用来描述动态场景的JSON架构的语言,主要用于Cesium在浏览器中的展示。它可以用来描述点、线、布告板、模型以及其他的图元,同时定义他们是怎样随时间变化的[3]。

CZML可使用model属性直接加载3D模型,由position属性决定模型在世界坐标系内的位置,由orientation决定模型在世界坐标系内的姿态,并最终由orientation的unitQuaternion表示。

unitQuaternion即单位四元数,可与偏航俯仰滚转相互转换,并避免偏航俯仰滚转的万向节锁定问题,但其本质上都是一个旋转矩阵,可决定模型在世界坐标系内的姿态。

获取正确的飞行器姿态

首先计算飞行器模型坐标系对站点直角坐标系的旋转矩阵(在制作飞行器3D模型时,应使其中心在本地坐标系原点,机头机翼与轴平行,方便计算在站点直角坐标系内的旋转角度),再乘以由飞行器偏航俯仰滚转得到的旋转矩阵,再乘以站点直角坐标系对世界坐标系的旋转矩阵。将最终得到旋转矩阵转换为单位四元数,即得到正确的飞行器姿态。

小技巧:飞机3D模型的中心设置在本地坐标系原点,机头机翼与轴平行后,可能在Cesium中渲染时姿态还是不对。原因是绕Z轴旋转的角度还是不对。可以在HeadingPitchRoll示例中使用自己的飞机3D模型,参照Cesium给的运输机模型,比较它们之间绕Z轴旋转的差异,然后调整飞机3D模型绕Z轴旋转的角度。

解决方法

参考代码如下:

1
2
3
4
5
6
var lon=113,lat=34;//模型的站心经纬度
var h1=0,p1=0,r1=0;//模型坐标系对站点坐标系的旋转角度
var h2=0,p2=0,r2=0;//模型在站点坐标系的姿态
var center = Cesium.Cartesian3.fromDegrees(lon, lat)
var hpr = new Cesium.HeadingPitchRoll(h1+h2, p1+p2, r1+r2)
var q1 = Cesium.Transforms.headingPitchRollQuaternion(center, hpr)

参考链接

  1. CESIUM : How to animate an aircraft from pitch, roll, heading?, by stackoverflow.
  2. Cesium中的几种坐标和相互转换, by finalLi.
  3. Cesium Language (CZML) 入门1 — CZML Structure(CZML的结构), by laixiangran.
  4. CZML Structure, by AnalyticalGraphicsInc.
  5. 3D坐标系, by S_H_C.
  6. 3D空间的坐标系, by trojanpizza.
  7. cesium获取某个位置垂直于当前地表的垂直坐标系,by 暮志未晚Webgl.
  8. Cesium控制模型旋转2019-11-15,by _____xyz.

春江花月夜

发表于 2018-06-09
作者:张若虚 春江潮水连海平,海上明月共潮生。 滟滟随波千万里,何处春江无月明? 江流宛转绕芳甸,月照花林皆似霰。 空里流霜不觉飞,汀上白沙看不见。 江天一色无纤尘,皎皎空中孤月轮。 江畔何人初见月,江月何年初照人? 人生代代无穷已,江月年年祇相似。 不知江月待何人?但见长江送流水。 白云一片去悠悠,青枫浦上不胜愁。 谁家今夜扁舟子,何处相思明月楼? 可怜楼上月徘徊,应照离人妆镜台。 玉户帘中卷不去,捣衣砧上拂还来。 此时相望不相闻,愿逐月华流照君。 鸿雁长飞光不度,鱼龙潜跃水成文。 昨夜闲潭梦落花,可怜春半不还家。 江水流春去欲尽,江潭落月复西斜。 斜月沉沉藏海雾,碣石潇湘无限路。 不知乘月几人归,落月摇情满江树。

Cesium小部件animation和timeline的系统时间显示

发表于 2018-06-09 | 更新于 2019-12-26

Cesium的小部件animation和timeline显示UTC系统时间,需要将其改为本地系统时间。修改方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
this.viewer.animation.viewModel.dateFormatter = localeDateTimeFormatter
this.viewer.animation.viewModel.timeFormatter = localeTimeFormatter
this.viewer.timeline.makeLabel = function (time) { return localeDateTimeFormatter(time) }

// Date formatting to a global form
function localeDateTimeFormatter(datetime, viewModel, ignoredate) {
var julianDT = new Cesium.JulianDate();
Cesium.JulianDate.addHours(datetime,8,julianDT)
var gregorianDT= Cesium.JulianDate.toGregorianDate(julianDT)
var objDT;
if (ignoredate)
objDT = '';
else {
objDT = new Date(gregorianDT.year, gregorianDT.month - 1, gregorianDT.day);
objDT = gregorianDT.year + '年' +objDT.toLocaleString("zh-cn", { month: "short" })+ gregorianDT.day + '日' ;
if (viewModel || gregorianDT.hour + gregorianDT.minute === 0)
return objDT;
objDT += ' ';
}
return objDT + Cesium.sprintf("%02d:%02d:%02d", gregorianDT.hour, gregorianDT.minute, gregorianDT.second);
}

function localeTimeFormatter(time, viewModel) {
return localeDateTimeFormatter(time, viewModel, true);
}

上述代码还存在一个问题,当timeline小部件不活动时,其仍然显示UTC标准系统时间。

Cesium的credit十分碍眼,采用如下方法去掉:

1
2
//去除版权信息
viewer._cesiumWidget._creditContainer.style.display = "none";

参考链接

  1. EST,CST,PST,GMT,UTC,EDT等等时间缩写, by chienchia.
  2. Change UTC timezone to SGT timezone in Cesiumjs, by stackoverflow.
  3. Cesium去掉logo,by 跃然实验室.

Matplotlib蜡烛图绘制教程

发表于 2018-06-03 | 更新于 2020-01-01

股票分析离不开各种图表的绘制,尤其是最常用的蜡烛图。下面介绍python中使用matplotlib绘制蜡烛图的过程。

环境及配置

使用的环境如下:

1
2
3
4
5
6
7
8
9
10
11
12
$ python3 --version
Python 3.6.5rc1
$ ipython3
In [1]: import matplotlib
In [2]: matplotlib.__version__
Out[2]: '2.2.2'
In [3]: import tushare as ts
In [4]: ts.__version__
Out[4]: '1.1.9'
In [5]: import talib
In [6]: talib.__version__
Out[6]: '0.4.17'

绘制蜡烛图通常使用matplotlib.finance库,但这个库在matplotlib 2.0后已经被废弃,并被移到一个名叫mpl_finance的库中。可使用如下命令安装mpl_finance。

1
pip3 install https://github.com/matplotlib/mpl_finance/archive/master.zip

mpl_finance使用雅虎接口获取股票数据,但是不稳定,因此推荐使用tushare库获取股票数据。另外使用talib计算股票各种技术分析指标,例如常用的均线数据。需要注意的是通过pip3按照的talib库是对C/C++版talib的包装,因此需先安装C/C++版talib。

蜡烛图绘制

蜡烛图绘制函数简介

mpl_finance库中蜡烛图的绘制主要有以下四个函数:

1
2
3
4
candlestick2_ochl(ax, opens, closes, highs, lows, width=4, colorup='k', colordown='r', alpha=0.75)
candlestick2_ohlc(ax, opens, highs, lows, closes, width=4, colorup='k', colordown='r', alpha=0.75)
candlestick_ochl(ax, quotes, width=0.2, colorup='k', colordown='r', alpha=1.0)
candlestick_ohlc(ax, quotes, width=0.2, colorup='k', colordown='r', alpha=1.0)

在这四个函数的使用过程中需要注意的是:

  • candlestick2_ohlc函数假定opens, highs, lows, closes中任意一个值不存在,则其他值也不存在。

  • candlestick_ochl和candlestick_ohlc的输入参数quotes是(time, open, close, high, low, …)元组序列,其中time必须是浮点日期格式,具体参见date2num。

蜡烛图绘制函数存在日线图的时间间隔问题(非交易日无法跳过,导致图像断裂)。常用解决方法是建议重新调整横坐标,被动地过滤掉非交易时间段[2]。例如:

1
2
ax.set_xticks(range(0, len(data['date']), 10))
ax.set_xticklabels(data['date'][::10])

蜡烛图的简单绘制

蜡烛图的简单例子如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import numpy as np
import talib
import tushare as ts
import matplotlib.pyplot as plt
import mpl_finance as mpf

data = ts.get_k_data('002320')
sma_10 = talib.SMA(np.array(data['close']), 10)
sma_30 = talib.SMA(np.array(data['close']), 30)
fig = plt.figure(figsize=(24, 8))
ax = fig.add_subplot(1, 1, 1)
ax.set_xticks(range(0, len(data['date']), 50))
ax.set_xticklabels(data['date'][::50])
ax.plot(sma_10, label='10 日均线')
ax.plot(sma_30, label='30 日均线')
ax.legend(loc='upper left')
mpf.candlestick2_ochl(ax, data['open'], data['close'], data['high'], data['low'],width=0.5, colorup='r', colordown='green',alpha=0.6)
plt.grid()
plt.show()

参考链接

  1. finance api, by matplotlib

matplotlib用法笔记

发表于 2018-05-26 | 更新于 2020-01-05

matplotlib 是Python编程语言及其数值数学扩展包 NumPy的可视化操作界面。它为利用通用的图形用户界面工具包,如Tkinter, wxPython, Qt或GTK+向应用程序嵌入式绘图提供了应用程序接口(API)。此外,matplotlib还有一个基于图像处理库(如开放图形库OpenGL)的pylab接口,其设计与MATLAB非常类似–尽管并不怎么好用。SciPy就是用matplotlib进行图形绘制。

绘图结构

matplotlib API包含有三层:

  • backend_bases.FigureCanvas : 图表的绘制领域
  • backend_bases.Renderer : 知道如何在FigureCanvas上如何绘图
  • artist.Artist : 知道如何使用Renderer在FigureCanvas上绘图

FigureCanvas和Renderer需要处理底层的绘图操作,例如使用wxPython在界面上绘图,或者使用PostScript绘制PDF。Artist则处理所有的高层结构,例如处理图表、文字和曲线等的绘制和布局。通常我们只和Artist打交道,而不需要关心底层的绘制细节。

Artists分为简单类型和容器类型两种。简单类型的Artists为标准的绘图元件,例如Line2D、 Rectangle、 Text、AxesImage 等等。而容器类型则可以包含许多简单类型的Artists,使它们组织成一个整体,例如Axis、 Axes、Figure等。

matplotlib pyplot绘图结构

图1 matplotlib pyplot绘图结构

基本用法

使用plt.figure定义一个图像窗口。

1
2
3
4
5
6
7
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-1, 1, 50)
y = 2*x + 1
plt.figure()
plt.plot(x, y)
plt.show()

设置标题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 导入matplotlib库
import matplotlib
import matplotlib.pyplot as plt
# %matplotlib inline 显示图表
# 使用'ggplot'风格美化显示的图表
plt.style.use('ggplot')

# 设置使用的字体(需要显示中文的时候使用)
font = {'family':'SimHei'}
matplotlib.rc('font',**font)

# 当坐标轴有负号的时候可以显示负号
matplotlib.rcParams['axes.unicode_minus']=False

# 设置标题
plt.title('正弦函数',fontsize=20) 设置子图表标题和标题字体的大小

设置坐标轴

使用plt.xlim设置x坐标轴范围:(-1, 2); 使用plt.ylim设置y坐标轴范围:(-2, 3);
使用plt.xlabel设置x坐标轴名称:’I am x’; 使用plt.ylabel设置y坐标轴名称:’I am y’;

1
2
3
4
plt.xlim((-1, 2))
plt.ylim((-2, 3))
plt.xlabel('I am x')
plt.ylabel('I am y')

使用np.linspace定义范围以及个数:范围是(-1,2);个数是5. 使用print打印出新定义的范围. 使用plt.xticks设置x轴刻度:范围是(-1,2);个数是5.

1
2
3
new_ticks = np.linspace(-1, 2, 5)
print(new_ticks)
plt.xticks(new_ticks)

使用plt.yticks设置y轴刻度以及名称:刻度为[-2, -1.8, -1, 1.22, 3];对应刻度的名称为[‘really bad’,’bad’,’normal’,’good’, ‘really good’]. 使用plt.show显示图像.

1
2
plt.yticks([-2, -1.8, -1, 1.22, 3],[r'$really\ bad$', r'$bad$', r'$normal$', r'$good$', r'$really\ good$'])
plt.show()

使用plt.gca获取当前坐标轴信息. 使用.spines设置边框:右侧边框;使用.set_color设置边框颜色:默认白色; 使用.spines设置边框:上边框;使用.set_color设置边框颜色:默认白色;

1
2
3
4
ax = plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
plt.show()

调整坐标轴

使用.xaxis.set_ticks_position设置x坐标刻度数字或名称的位置:bottom.(所有位置:top,bottom,both,default,none)

1
ax.xaxis.set_ticks_position('bottom')

使用.spines设置边框:x轴;使用.set_position设置边框位置:y=0的位置;(位置所有属性:outward,axes,data)
使用.yaxis.set_ticks_position设置y坐标刻度数字或名称的位置:left.(所有位置:left,right,both,default,none)
使用.spines设置边框:y轴;使用.set_position设置边框位置:x=0的位置;(位置所有属性:outward,axes,data) 使用plt.show显示图像.

1
2
3
4
ax.spines['bottom'].set_position(('data', 0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data',0))
plt.show()

legend图例

基本用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-3, 3, 50)
y1 = 2*x + 1
y2 = x**2

plt.figure()
#set x limits
plt.xlim((-1, 2))
plt.ylim((-2, 3))

# set new sticks
new_sticks = np.linspace(-1, 2, 5)
plt.xticks(new_sticks)
# set tick labels
plt.yticks([-2, -1.8, -1, 1.22, 3],
[r'$really\ bad$', r'$bad$', r'$normal$', r'$good$', r'$really\ good$'])

# set line syles
l1, = plt.plot(x, y1, label='linear line')
l2, = plt.plot(x, y2, color='red', linewidth=1.0, linestyle='--', label='square line')

plt.legend(loc='upper right')

调整位置和名称

1
plt.legend(handles=[l1, l2], labels=['up', 'down'],  loc='best')

其中’loc’参数有多种,’best’表示自动分配最佳位置。

1
2
3
4
5
6
7
8
9
10
11
'best' : 0,          
'upper right' : 1,
'upper left' : 2,
'lower left' : 3,
'lower right' : 4,
'right' : 5,
'center left' : 6,
'center right' : 7,
'lower center' : 8,
'upper center' : 9,
'center' : 10,

子图

使用plt.subplot来创建小图。 plt.subplot(2,2,1)表示将整个图像窗口分为2行2列, 当前位置为1。 使用plt.plot([0,1],[0,1])在第1个位置创建一个小图。

1
2
3
4
import matplotlib.pyplot as plt
fig=plt.figure()
ax = fig.add_subplot(2, 2, 1, projection='3d')
ax.plot([0,1,1],[0,1,1])

plt.subplot(222)表示将整个图像窗口分为2行2列, 当前位置为2. 使用plt.plot([0,1],[0,2])在第2个位置创建一个小图.

1
2
plt.subplot(222)
plt.plot([0,1],[0,2])

动画

Matplotlib使用FuncAnimation函数生成动画。参数说明:

  • fig 进行动画绘制的figure
  • func 自定义动画函数,即传入刚定义的函数animate
  • frames 动画长度,一次循环包含的帧数
  • init_func 自定义开始帧,即传入刚定义的函数init
  • interval 更新频率,以ms计
  • blit 选择更新所有点,还是仅更新产生变化的点。应选择True,但mac用户请选择False,否则无法显示动画
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from matplotlib import pyplot as plt
from matplotlib import animation
import numpy as np

fig, ax = plt.subplots()

x = np.arange(0, 2*np.pi, 0.01)
line, = ax.plot(x, np.sin(x))

def animate(i):
line.set_ydata(np.sin(x + i/10.0))
return line,

def init():
line.set_ydata(np.sin(x))
return line,
//注意此处FuncAnimation必须有返回值
ani = animation.FuncAnimation(fig=fig,
func=animate,
frames=100,
init_func=init,
interval=20,
blit=False)

plt.show()

参考链接

  1. matplotlib, by wikipedia
  2. 莫烦Python, by morvanzhou
  3. API Overview,by matplotlib.
  4. Python matplotlib高级绘图详解,by 微岩.
  5. 用Matplotlib制作动画,by 段丞博.
  6. Plot inline or a separate window using Matplotlib in Spyder IDE,by stackoverflow.
  7. Python之matplotlib的使用汇总,by 探索数据之美.

python3与python2的区别与兼容

发表于 2018-05-26 | 更新于 2018-10-09

Python是一种广泛使用的高级编程语言,属于通用型编程语言,由吉多·范罗苏姆创造,第一版发布于1991年。可以视之为一种改良(加入一些其他编程语言的优点,如面向对象)的LISP。作为一种解释型语言,Python的设计哲学强调代码的可读性和简洁的语法(尤其是使用空格缩进划分代码块,而非使用大括号或者关键词)。相比于C++或Java,Python让开发者能够用更少的代码表达想法。不管是小型还是大型程序,该语言都试图让程序的结构清晰明了。

与Scheme、Ruby、Perl、Tcl等动态类型编程语言一样,Python拥有动态类型系统和垃圾回收功能,能够自动管理内存使用,并且支持多种编程范式,包括面向对象、命令式、函数式和过程式编程。其本身拥有一个巨大而广泛的标准库。

Python 解释器本身几乎可以在所有的操作系统中运行。Python的正式解释器CPython是用C语言编写的、是一个由社区驱动的自由软件,目前由Python软件基金会管理。

python3与python2区别

print函数

Python 2 的 print 声明在Python 3中已经被 print() 函数取代

1
2
3
4
5
#!/usr/bin/python2
print 'Hello, World!'

#!/usr/bin/python3
print('Hello, World!')

整除

/是精确除法,//是向下取整除法,%是求模。

//和%运算符在2和3版本中一样,但是运算符/不一样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/python2
>>> 3 / 2
1
>>> 3 // 2
1
>>> 3 / 2.0
1.5
>>> 3 // 2.0
1.0

#!/usr/bin/python3
>>> 3 / 2
1.5
>>> 3 // 2
1
>>> 3 / 2.0
1.5
>>> 3 // 2.0
1.0

Unicode

由于历史遗留问题,Python 2.x版本虽然支持Unicode,但在语法上需要’xxx’和u’xxx’两种字符串表示方式。

在Python 3.x版本中,把’xxx’和u’xxx’统一成Unicode编码,即写不写前缀u都是一样的,而以字节形式表示的字符串则必须加上b前缀:b’xxx’。

1
2
3
4
5
6
#!/usr/bin/python2

#!/usr/bin/python3
>>> 中国 = 'china'
>>> print(中国)
china

xrange模块

在 Python 2 中 xrange() 创建迭代对象的用法是非常流行的。比如: for 循环或者是列表/集合/字典推导式。

在 Python 3 中,range() 是像 xrange() 那样实现以至于一个专门的 xrange() 函数都不再存在(在 Python 3 中 xrange() 会抛出命名异常)。

不等运算符

Python 2.x中不等于有两种写法 != 和 <>

Python 3.x中去掉了<>, 只有!=一种写法

数据类型

  • Py3.X去除了long类型,现在只有一种整型——int,但它的行为就像2.X版本的long
  • 新增了bytes类型,对应于2.X版本的八位串
  • dict的.keys()、.items 和.values()方法返回迭代器,而之前的iterkeys()等函数都被废弃。同时去掉的还有 dict.has_key(),用 in替代它吧 。

异常

  • 在 Python 3 中处理异常也轻微的改变了,在 Python 3 中我们现在使用 as 作为关键词。
  • 捕获异常的语法由 except exc, var 改为 except exc as var。
    使用语法except (exc1, exc2) as var可以同时捕获多种类别的异常。 Python 2.6已经支持这两种语法。

解析用户的输入

  • 在python2.x中raw_input()和input(),两个函数都存在,其中区别为

    raw_input()—将所有输入作为字符串看待,返回字符串类型

    input()—–只能接收“数字”的输入,在对待纯数字输入时具有自己的特性,它返回所输入的数字的类型(int, float)

  • 在python3.x中raw_input()和input()进行了整合,去除了raw_input(),仅保留了input()函数,其接收任意任性输入,将所有输入默认为字符串处理,并返回字符串类型。

返回可迭代对象,而不是列表

如果在 xrange 章节看到的,现在在 Python 3 中一些方法和函数返回迭代对象 — 代替 Python 2 中的列表。

因为我们通常那些遍历只有一次,我认为这个改变对节约内存很有意义。尽管如此,它也是可能的,相对于生成器 —- 如需要遍历多次。它是不那么高效的。

而对于那些情况下,我们真正需要的是列表对象,我们可以通过 list() 函数简单的把迭代对象转换成一个列表。

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/python2
>>> print range(3)
[0, 1, 2]
>>> print type(range(3))
<type 'list'>

#!/usr/bin/python3
>>> print(range(3))
range(0, 3)
>>> print(type(range(3)))
<class 'range'>
>>> print(list(range(3)))
[0, 1, 2]

For循环变量和全局命名空间泄漏

在 Python 3.x 中 for 循环变量不会再导致命名空间泄漏。

在 Python 3.x 中做了一个改变,在 What’s New In Python 3.0 中有如下描述:
“列表推导不再支持 [… for var in item1, item2, …] 这样的语法。使用 [… for var in (item1, item2, …)] 代替。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/python2
>>> i = 1
>>> print 'before: i =', i
before: i = 1
>>> print 'comprehension: ', [i for i in range(5)]
comprehension: [0, 1, 2, 3, 4]
>>> print 'after: i =', i
after: i = 4

#!/usr/bin/python3
>>> i = 1
>>> print('before: i =', i)
before: i = 1
>>> print('comprehension:', [i for i in range(5)])
comprehension: [0, 1, 2, 3, 4]
>>> print('after: i =', i)
after: i = 1

兼容python3与python2

当前python3的普及还不尽人意,因此编写的python程序能同时兼容python2与python3是十分必要的。下面介绍同时支持python2与python3的方法。

  • 放弃python 2.6之前的python版本
  • 使用 2to3 工具对代码检查
  • 使用python -3执行python程序
  • from future import
    “from future import”后即可使使用python的未来特性了。python的完整future特性可见 future 。python3中所有字符都变成了unicode。在python2中unicode字符在定义时需要在字符前面加 u,但在3中则不需要家u,而且在加u后程序会无法编译通过。为了解决该问题可以 “from future import unicode_literals” ,这样python2中字符的行为将和python3中保持一致,python2中定义普通字符将自动识别为unicode。
  • import问题
    python3中“少”了很多python2的包,在大多情况下这些包之是改了个名字而已。我们可以在import的时候对这些问题进行处理。
    1
    2
    3
    4
    5
    6
    7
    try:#python2
    from UserDict import UserDict
    #建议按照python3的名字进行import
    from UserDict import DictMixin as MutableMapping
    except ImportError:#python3
    from collections import UserDict
    from collections import MutableMapping
  • 使用python3的方式写程序
  • 检查当前运行的python版本
    1
    2
    3
    4
    5
    import sys
    if sys.version > '3':
    PY3 = True
    else:
    PY3 = False
  • six
    不推荐使用six。

参考链接

  1. https://zh.wikipedia.org/wiki/Python, by wikipedia
  2. https://www.jianshu.com/p/85583e032eb8, by EarthChen
  3. http://python.jobbole.com/83987/, by 天地一沙鸥

Git用法总结

发表于 2018-05-24 | 更新于 2025-02-27

git是一个分布式版本控制软件,最初由林纳斯·托瓦兹(Linus Torvalds)创作,于2005年以GPL发布。最初目的是为更好地管理Linux内核开发而设计[1]。

git结构

新建代码库

1
2
3
4
5
6
7
8
# 在当前目录新建一个Git代码库
$ git init

# 新建一个目录,将其初始化为Git代码库
$ git init [project-name]

# 下载一个项目和它的整个代码历史
$ git clone [url]

配置

Git的设置文件为.gitconfig,它可以在用户主目录下(全局配置),也可以在项目目录下(项目配置)。

1
2
3
4
5
6
7
8
9
# 显示当前的Git配置
$ git config --list

# 编辑Git配置文件
$ git config -e [--global]

# 设置提交代码时的用户信息
$ git config [--global] user.name "[name]"
$ git config [--global] user.email "[email address]"

代码提交

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 提交暂存区到仓库区
$ git commit -m [message]

# 提交暂存区的指定文件到仓库区
$ git commit [file1] [file2] ... -m [message]

# 提交工作区自上次commit之后的变化,直接到仓库区
$ git commit -a

# 提交时显示所有diff信息
$ git commit -v

# 使用一次新的commit,替代上一次提交
# 如果代码没有任何新变化,则用来改写上一次commit的提交信息
$ git commit --amend -m [message]

# 重做上一次commit,并包括指定文件的新变化
$ git commit --amend [file1] [file2] ...

查看信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# 显示有变更的文件
$ git status

# 显示当前分支的版本历史
$ git log

# 显示commit历史,以及每次commit发生变更的文件
$ git log --stat

# 搜索提交历史,根据关键词
$ git log -S [keyword]

# 显示某个commit之后的所有变动,每个commit占据一行
$ git log [tag] HEAD --pretty=format:%s

# 显示某个commit之后的所有变动,其"提交说明"必须符合搜索条件
$ git log [tag] HEAD --grep feature

# 显示某个文件的版本历史,包括文件改名
$ git log --follow [file]
$ git whatchanged [file]

# 显示指定文件相关的每一次diff
$ git log -p [file]

# 显示过去5次提交
$ git log -5 --pretty --oneline

# 显示所有提交过的用户,按提交次数排序
$ git shortlog -sn

# 显示指定文件是什么人在什么时间修改过
$ git blame [file]

# 显示暂存区和工作区的差异
$ git diff

# 显示暂存区和上一个commit的差异
$ git diff --cached [file]

# 显示工作区与当前分支最新commit之间的差异
$ git diff HEAD

# 显示两次提交之间的差异
$ git diff [first-branch]...[second-branch]

# 显示今天你写了多少行代码
$ git diff --shortstat "@{0 day ago}"

# 显示某次提交的元数据和内容变化
$ git show [commit]

# 显示某次提交发生变化的文件
$ git show --name-only [commit]

# 显示某次提交时,某个文件的内容
$ git show [commit]:[filename]

# 显示当前分支的最近几次提交
$ git reflog

Git 工具 - 子模块

有种情况我们经常会遇到:某个工作中的项目需要包含并使用另一个项目。 也许是第三方库,或者你独立开发的,用于多个父项目的库。 现在问题来了:你想要把它们当做两个独立的项目,同时又想在一个项目中使用另一个。

Git 通过子模块来解决这个问题。 子模块允许你将一个 Git 仓库作为另一个 Git 仓库的子目录。 它能让你将另一个仓库克隆到自己的项目中,同时还保持提交的独立。

1
2
3
4
5
6
7
$ git submodule add https://github.com/chaconinc/DbConnector
Cloning into 'DbConnector'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 11 (delta 0), reused 11 (delta 0)
Unpacking objects: 100% (11/11), done.
Checking connectivity... done.

默认情况下,子模块会将子项目放到一个与仓库同名的目录中,本例中是 “DbConnector”。 如果你想要放到其他地方,那么可以在命令结尾添加一个不同的路径。

Git代理设置

1
2
3
4
5
6
7
8
9
10
git config --global https.proxy http://127.0.0.1:1080

git config --global https.proxy https://127.0.0.1:1080

git config --global --unset http.proxy

git config --global --unset https.proxy


npm config delete proxy

不常用操作

  • 查看代码仓库中标签

    1
    git tag
  • 检出指定标签代码

    1
    git checkout tag_name
  • 丢弃本地修改

    1
    git checkout .
  • 打包导出仓库代码

    1
    git archive --format zip --output ..\emsdk\zips\1.38.8.zip HEAD

参考链接

  1. Git, by wikipedia
  2. git 如何获取指定 tag 代码, by 一介布衣
  3. 常用 Git 命令清单,by 阮一峰.
  4. 7.11 Git 工具 - 子模块,by git.
  5. Git submodule用法,by jinlei_123.

Vue.js集成three.js

发表于 2018-05-13 | 更新于 2023-03-23

Three.js是一个跨浏览器的脚本,使用JavaScript函数库或API来在网页浏览器中创建和展示动画的三维计算机图形。Three.js使用WebGL。源代码托管在GitHub。

下面介绍在Vue.js中集成three.js的步骤。

  1. 安装vue-cli脚手架
  2. 安装three.js
    1
    npm install --save three
  3. 编写使用three.js创建3D场景的Vuejs组件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    <template>
    <div id="container"></div>
    </template>
    <script>
    import * as Three from 'three'

    export default {
    name: 'Home',
    data () {
    return {
    camera: null,
    scene: null,
    renderer: null,
    mesh: null
    }
    },
    methods: {
    init: function () {
    var container = document.getElementById('container')

    this.camera = new Three.PerspectiveCamera(70, container.clientWidth / container.clientHeight, 0.01, 10)
    this.camera.position.z = 1

    this.scene = new Three.Scene()

    var geometry = new Three.BoxGeometry(0.2, 0.2, 0.2)
    var material = new Three.MeshNormalMaterial()

    this.mesh = new Three.Mesh(geometry, material)
    this.scene.add(this.mesh)

    this.renderer = new Three.WebGLRenderer({ antialias: true })
    this.renderer.setSize(container.clientWidth, container.clientHeight)
    container.appendChild(this.renderer.domElement)
    },
    animate: function () {
    requestAnimationFrame(this.animate)
    this.mesh.rotation.x += 0.01
    this.mesh.rotation.y += 0.02
    this.renderer.render(this.scene, this.camera)
    }
    },
    mounted () {
    this.init()
    this.animate()
    }
    }

    </script>
    <style rel="stylesheet/scss" lang="scss" scoped>
    #container {
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    overflow: hidden;
    }

    </style>

参考链接

  1. Three.js, by Wikipedia
  2. Import and use three.js library in vue component, by Stackoverlflow

Windows批处理编程语法解析

发表于 2018-05-13 | 更新于 2024-03-04

批处理文件(BAT文件)是DOS,OS/2和Microsoft Windows中的一种脚本文件[1]。 它由命令行解释器执行的一系列命令组成,存储在纯文本文件中,通常以BAT为扩展名。批处理文件可以包含解释器交互接受的任何命令,并使用在批处理文件中启用条件分支和循环的构造,如IF,FOR和GOTO标签。在Windows平台自动化部署或处理日常重复性工作时,常使用Windows批处理文件。

批处理命令简介

下面简单介绍Windows BAT文件的语法。

变量操作

  • 设置变量

格式:set 变量名=变量值
详细:被设定的变量以%变量名%引用

  • 取消变量
    格式:set 变量名=
    详细:取消后的变量若被引用%变量名%将为空

  • 展示变量
    格式:set 变量名
    详细:展示以变量名开头的所有变量的值

  • 列出所有可用的变量
    格式:set

常用命令

  • @

让执行窗口中不显示它后面这一行的命令本身。

1
2
// 使用@将不显示后面的echo off命令
@ echo off
  • echo

echo即回显或反馈的意思。它由两种状态:打开和关闭。

1
2
3
4
// 将不显示后续的命令
@ echo off
// 将显示后续的命令
@ echo on
  • ::

注释命令。在批处理文件中与rem命令等效

  • call

call命令用来从一个批处理文件调用另一个批处理文件。只有当被调用的批处理文件执行完成时,才返回。

1
call pm2-startup install
  • start

启动单独的“命令提示符”窗口来运行指定程序或命令。如果在没有参数的情况下使用,start 将打开第二个命令提示符窗口。

  • pause

暂停命令。方便用户查看信息,查看完毕后可继续执行。

  • explorer

在 cmd 下输入explorer可打开文件夹图形界面,例如:

1
2
// 在图形界面中打开当前文件夹
explorer .
  • %i

for循环在cmd命令行中的固定用法for %i in (set) do (…),循环变量格式为%i

1
for %i in (1,2,3,5,8) do echo %i
  • %%i

for循环在bat处理程序中的固定用法for %%i in (set) do (…),循环变量格式为%%i

  • &

顺序执行多条命令,而不管命令是否执行成功

  • &&

顺序执行多条命令,当碰到执行出错的命令后将不执行后面的命令

  • ||

顺序执行多条命令,当碰到执行正确的命令后将不执行后面的命令(即:只有前面命令执行错误时才执行后面命令)

  • |

管道命令 前一个命令的执行结果输出到后一个命令 如:help|more

清除文件中原有的内容后再写入

追加内容到文件末尾,而不会清除原有的内容主要将本来显示在屏幕上的内容输出到指定文件中指定文件如果不存在,则自动生成该文件。

1
certutil -hashfile user-history.db md5 >> hash.txt
  • cd /d %~dp0
1
2
3
4
5
6
/d 表示直接切换到对应分区
%0代表批处理本身 d:\qq\a.bat
~dp是变量扩充
d既是扩充到分区号 d:
p就是扩充到路径 \qq
dp就是扩充到分区号路径 d:\qq

批处理脚本示例

示例1:

1
2
3
4
5
6
7
8
9
10
11
12
@echo off
set PATH=E:\Simulation\x64\Release\;%PATH%;
E:
cd E:\Simulation\x64\Release\
cd BlueSimu
start FlightSimServer.exe
cd ../RedSimu
start FlightSimServer.exe
cd ..
start Simulation.exe
start Simulation.exe
pause

示例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
:: 定义变量
set dataset=j:\tensorflow\dataset\LSOTB-TIR\Training Dataset
set imagedir=%dataset%\LSOTB-TIR_TrainingData\TrainingData\TIR_training_004\bird_001
set xmldir=%dataset%\LSOTB-TIR_TrainingData\Annotations\TIR_training_004\bird_001
set labelpath=j:\tensorflow\workspace\training_demo\annotations\label_map.pbtxt
set outputdir=j:\tensorflow\workspace\training_demo\annotations\infrared_train_bird_004_001
set process_script=j:\tensorflow\scripts\preprocessing\generate_pascal_tfrecord.py

:: 调用tfrecord脚本程序, for循环,字符串截取,字符串拼接,路径空格处理
for /L %%i in (1,1,7) do python %process_script% -i "%imagedir:~0,-1%%%i" -x "%xmldir:~0,-1%%%i" -l %labelpath% -o %outputdir:~0,-1%%%i.record
:: for /L %%i in (10,1,16) do python %process_script% -i "%imagedir:~0,-2%%%i" -x "%xmldir:~0,-2%%%i" -l %labelpath% -o %outputdir:~0,-2%%%i.record

pause

参考链接

  1. Batch file,by Wikipedia.
  2. 批处理最完整人性化教程(.bat文件语法), by s1ihome.
  3. 批处理命令之Start的详细用法,by QiaoZhi.
  4. windows批处理set命令,by 鹤唳九天.
  5. windows批处理——变量,命令换行,by undefined.
  6. Batch批处理字符串操作、for循环学习记录,by blingbling_110.
  7. .bat批处理(八):各种形式的变量%0、%i、%%i、var、%var%、!var!的含义和区别,by AlbertS.
  8. Bat命令学习-批处理中的&、&&、|、||、>、>>符号,by iloli.
  9. Windows certutil.exe 命令 简单举例 计算MD5与SHA1/256,by ldq_sd.
  10. cmd: cd /D %~dp0 的含义,by Nemo_XP.
  11. CMD获取当前目录的绝对路径 (当前盘符和路径:%~dp0),by 亟待!.

Vue.js集成Cesium

发表于 2018-05-11 | 更新于 2019-07-18

近期在研究集成封装Cesium为Vue.js组件,记录一下过程,防止忘了。

安装环境

  • node.js: v8.9.4
  • npm: 5.6.0
  • vue: 2.5.2
  • cesium: 1.45.0
  • vue-cli: 2.9.3
  • webpack: 3.6.0

注意此处vue-cli版本是2,因此该教程不适用vue-cli 3。如需在Vue-cli 3中构建Cesium,请参考Vue-cli 3.0 + cesium 构建.

安装配置

  1. 安装nodejs
  2. 安装vue-cli脚手架
    1
    2
    3
    4
    5
    npm install -g vue-cli
    vue init webpack my-project
    cd my-project
    npm install
    npm run dev
  3. 安装cesium
    1
    npm install --save cesium
  4. webpack配置
  • 在build/webpack.base.conf.js文件中做如下修改

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    //定义cesium源代码位置
    const cesiumSource = '../node_modules/cesium/Source'
    ...
    module.exports = {
    ...
    output: {
    path: config.build.assetsRoot,
    filename: '[name].js',
    publicPath: process.env.NODE_ENV === 'production'
    ? config.build.assetsPublicPath
    : config.dev.assetsPublicPath,
    // Needed to compile multiline strings in Cesium
    sourcePrefix: ''
    },
    amd:{
    // Enable webpack-friendly use of require in Cesium
    toUrlUndefined: true
    },
    resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
    'vue$': 'vue/dist/vue.esm.js',
    '@': resolve('src'),
    //设置cesium的别名
    'cesium': path.resolve(__dirname, cesiumSource)
    }
    },
    module: {
    rules: [
    ...
    ],
    //不让Webpack打印载入特定库时候的警告
    unknownContextCritical: false
    },
    ...
    }
  • 在build/webpack.dev.conf.js文件中做如下修改

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    //定义 Cesium 源代码路径,前面没有../
    const cesiumSource = 'node_modules/cesium/Source'
    //定义 Cesium Workers 路径
    const cesiumWorkers = '../Build/Cesium/Workers'
    ...
    plugins: [
    ...
    new CopyWebpackPlugin([ { from: path.join(cesiumSource, cesiumWorkers), to: 'Workers' } ]),
    new CopyWebpackPlugin([ { from: path.join(cesiumSource, 'Assets'), to: 'Assets' } ]),
    new CopyWebpackPlugin([ { from: path.join(cesiumSource, 'Widgets'), to: 'Widgets' } ]),
    new webpack.DefinePlugin({
    // Define relative base path in cesium for loading assets
    CESIUM_BASE_URL: JSON.stringify('')
    })
    ...
    ]
  • 在build/webpack.prod.conf.js文件中做如下修改

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    //定义 Cesium 源代码路径,前面没有../
    const cesiumSource = 'node_modules/cesium/Source'
    //定义 Cesium Workers 路径
    const cesiumWorkers = '../Build/Cesium/Workers'
    ...
    plugins: [
    ...
    new CopyWebpackPlugin([ { from: path.join(cesiumSource, cesiumWorkers), to: 'Workers' } ]),
    new CopyWebpackPlugin([ { from: path.join(cesiumSource, 'Assets'), to: 'Assets' } ]),
    new CopyWebpackPlugin([ { from: path.join(cesiumSource, 'Widgets'), to: 'Widgets' } ]),
    new webpack.DefinePlugin({
    //定义 Cesium 从哪里加载资源,如果使用默认的'',却变成了绝对路径了,所以这里使用'./',使用相对路径
    CESIUM_BASE_URL: JSON.stringify('./')
    })
    ...
    ]

Vue.js组件编写

  • 在src/components下新建 CesiumViewer.vue vue组件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    <template>
    <div id="cesiumContainer">
    </div>
    </template>
    <script type="text/javascript">
    import Cesium from 'cesium/Cesium'
    import widgets from 'cesium/Widgets/widgets.css'

    export default {
    name: 'CesiumViewer',
    mounted () {
    var viewer = new Cesium.Viewer('cesiumContainer')
    }
    }

    </script>
    <style rel="stylesheet/scss" lang="scss" scoped>
    #cesiumContainer {
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    overflow: hidden;
    }
    </style>
  • 创建全局样式文件src/styles/index.scss,做如下修改
    1
    2
    3
    4
    5
    6
    7
    8
    html,
    body {
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    overflow: hidden;
    }
  • 在src/main.js中做如下修改
    1
    import '@/styles/index.scss' // global css

参考链接

  1. 基于webpack 构建Cesium + Vue 的应用, by QingMings
  2. Vue-cli 3.0 + cesium 构建,by QingMings.
  3. cesium-and-webpack, by cesiumjs.org
  4. vue-cli生成的项目,main.js引入scss时报错,by segmentfault.
上一页1…515253下一页

Jack Huang

528 日志
68 标签
© 2025 Jack Huang
由 Hexo 强力驱动
|
主题 — NexT.Muse