《地理坐标(经纬度坐标)和屏幕坐标(xy坐标)间的转换》的读后笔记
今天读了一下《地理坐标(经纬度坐标)和屏幕坐标(xy坐标)间的转换》,觉得内容很好,特摘录和附上自己的解释。
背景
在我们的屏幕上,有一张地图,这张地图经过缩放、平移、旋转,最终地理坐标和屏幕坐标的关系大致如下图所示:
这种关系要怎么描述呢?我们可以假设地图是一张纸,而屏幕是一堵墙。只要我们有两个图钉,我们就能把纸定在墙上。我们把这两个点称为锚点。锚点在屏幕坐标系上的坐标是(x1,y1)
和(x2,y2)
,对应在地理坐标系上的坐标是(lon1,lat1)
和(lon2,lat2)
。
那现在的问题就变成了,已知两个锚点的坐标,
(1)地理坐标转屏幕坐标:已知任意一点的地理坐标(lon,lat)
,求它在屏幕上的坐标(x,y)
(2)屏幕坐标转地理坐标:已知任意一点的屏幕坐标(x,y)
,求它的经纬度坐标(lon,lat)
lon 表示 longitude (纬度)
lat 表示 latitude (经度)
x,y 表示屏幕上的只是一个任意位置的坐标点
转换算法
1、铺垫内容-地理坐标平面化
在一个小范围内(例如是方圆几公里内),我们可以假设地面是平的,而不是弯的。如果经纬度都用弧度表示,那么1纬度方向对应的长度是:
1 纬 度 方 向 长 度 = R ⋅ l a t 1 纬度方向长度 = R \cdot lat 1纬度方向长度=R⋅lat
注意:此处的 lat 指的不是我们常用的纬度度数,而是纬度弧度。半径乘以弧度才能得到弧长!
度 数 360 = 弧 度 2 π \frac{度数}{360}=\frac{弧度}{2π} 360度数=2π弧度
故 弧度 = 度数 ⋅ π 180 \cdot \frac{ \pi }{180} ⋅180π
其中 R R R 是地球半径。 而相同经度间的距离会随着纬度的增加而减少,
在 l a t lat lat 这一纬度下,1经度方向对应的长度是:
1 经 度 方 向 长 度 = R ⋅ cos ( l a t ) ⋅ l o n 1 经度方向长度= R \cdot \cos{(lat)} \cdot lon 1经度方向长度=R⋅cos(lat)⋅lon
上式中的 R ⋅ cos ( l a t ) R \cdot \cos{(lat )} R⋅cos(lat) 就是上图中的某一纬度下的切面的半径,然后在半径乘以弧度。
那么,(lon,lat)
这个坐标平面化后的坐标就是: ( R ⋅ l o n ⋅ cos ( l a t ) , R ⋅ l a t ) (R \cdot lon \cdot \cos{(lat)},R \cdot lat) (R⋅lon⋅cos(lat),R⋅lat)
故,此坐标可以作为我们在某一个小的平面范围内的类似于x、y的坐标
由于我们是假定在小范围内纬度是不变的,故此时若我们有两个经度不同的点,求经度长度的差时,应该遵循:
d l e n l o n = R ⋅ l o n 2 ⋅ c o s ( l a t ) − R ⋅ l o n 1 ⋅ c o s ( l a t ) = R ( l o n 2 − l o n 1 ) ⋅ c o s ( l a t ) dlen_{lon} = R \cdot lon_2 \cdot cos (lat) - R \cdot lon_1 \cdot cos (lat) = R(lon_2 - lon_1 )\cdot cos (lat) dlenlon=R⋅lon2⋅cos(lat)−R⋅lon1⋅cos(lat)=R(lon2−lon1)⋅cos(lat)
其实上式中的求纬度长度差时用到的 l a t lat lat,使用 l a t 1 lat_1 lat1或者是 l a t 2 lat_2 lat2都对,因为我们在计算经度长度时视作一致。
如果求一个纬度长度差与经度长度差比值的话:
d l e n l a t d l e n l o n = R ⋅ l a t 2 − R ⋅ l a t 1 R ( l o n 2 − l o n 1 ) ⋅ c o s ( l a t ) \frac{dlen_{lat}}{dlen_{lon}} = \frac{R \cdot lat_2-R \cdot lat_1}{R(lon_2 - lon_1 )\cdot cos (lat)} dlenlondlenlat=R(lon2−lon1)⋅cos(lat)R⋅lat2−R⋅lat1
好,我们上下同时除以 R R R,可得
= l a t 2 − l a t 1 ( l o n 2 − l o n 1 ) ⋅ c o s ( l a t ) = \frac{lat_2- lat_1}{(lon_2 - lon_1 )\cdot cos (lat)} =(lon2−lon1)⋅cos(lat)lat2−lat1
又因为前面提到过,我们计算经度长度时视纬度为不变的,故我们随意地,把 l a t 2 lat_2 lat2 代给 l a t lat lat .
= l a t 2 − l a t 1 ( l o n 2 − l o n 1 ) ⋅ c o s ( l a t 2 ) = \frac{lat_2- lat_1}{(lon_2 - lon_1 )\cdot cos (lat_2)} =(lon2−lon1)⋅cos(lat2)lat2−lat1
这里需要注意的是: l a t 2 − l a t 1 ( l o n 2 − l o n 1 ) \frac{lat_2- lat_1}{(lon_2 - lon_1 )} (lon2−lon1)lat2−lat1 是个比值,故用度数比和弧度比都一致。但是, c o s ( l a t 2 ) cos (lat_2) cos(lat2) 处只能是弧度,原文的代码中有特别指出。
此二者的比值可以方便我们:
在得到经度时根据比值关系获得纬度
或
在得到纬度时根据比值关系获得经度
换到解方程组里就是y通过某种关系变成了能用x表示的式子,方程中只剩下一个未知数后,便可以求解。此刻,我们已经得到经纬度的代数关系,下面就是去根据向量法来把问题拉回到一个点上的经纬度以及xy之间的关系。
2、核心内容-向量法
由已知点和未知点组成两组向量:
由于坐标系转换是线性变换,所以两组向量有以下特性:
(1)两向量在不同的坐标系中的长度比是相同的。
(2)两向量在不同的坐标系中的夹角是相同的。
根据上面两个特性,我们可列出方程组:
下面提到的 d ,应该只是简单代指 difference (差值)
设向量1为 ( d x 1 , d y 1 ) (dx_1,dy_1) (dx1,dy1), ( d l o n 1 , d l a t 1 ) (dlon_1,dlat_1) (dlon1,dlat1),向量2为 ( d x 2 , d y 2 ) , ( d l o n 2 , d l a t 2 ) (dx_2,dy_2),(dlon_2,dlat_2) (dx2,dy2),(dlon2,dlat2),
由于把经度长度差写成 d l e n l o n dlen_{lon} dlenlon 把纬度长度差写成 d l e n l a t dlen_{lat} dlenlat 比较麻烦,这里简写成了 d l o n dlon dlon 和 d l a t dlat dlat 因为长度嘛,只能是线段长、弧长的比,不可能是直接的度数比。这里适应一下,提醒一下自己。
其中
d x 1 = x 2 − x 1 dx_1=x_2-x_1 dx1=x2−x1, d y 1 = y 2 − y 1 dy_1=y_2-y_1 dy1=y2−y1, d l o n 1 = l o n 2 − l o n 1 dlon_1=lon_2-lon_1 dlon1=lon2−lon1, d l a t 1 = l a t 2 − l a t 1 dlat_1=lat_2-lat_1 dlat1=lat2−lat1
d x 2 = x − x 1 dx_2=x-x_1 dx2=x−x1 , d y 2 = y − y 1 dy_2=y-y_1 dy2=y−y1 , d l o n 2 = l o n − l o n 1 dlon_2=lon-lon_1 dlon2=lon−lon1, d l a t 2 = l a t − l a t 1 dlat_2=lat-lat_1 dlat2=lat−lat1,
然后
k 1 = n o r m ( d x 1 , d y 1 ) k_1=norm(dx_1,dy_1) k1=norm(dx1,dy1)
k 2 = n o r m ( d l o n 1 , d l a t 1 ) k_2=norm(dlon_1,dlat_1) k2=norm(dlon1,dlat1)
k 3 = n o r m ( d x 2 , d y 2 ) k_3=norm(dx_2,dy_2) k3=norm(dx2,dy2)
k 4 = n o r m ( d l o n 2 , d l a t 2 ) k_4=norm(dlon_2,dlat_2) k4=norm(dlon2,dlat2)
这里的
norm
函数我查了一下,就是求范数,根据《np.linalg.norm(求范数)》 一文的介绍,向量的范数有计算公式,默认是求二范数,二范数就是向量的模长。
下面我们给出方程组:
- 根据前文中提到的 两向量在不同的坐标系中的长度比是相同的 可得到
k 1 k 2 = k 3 k 4 \frac{k_1}{k_2} = \frac{k_3}{k_4} k2k1=k4k3
本式当然可以写成:
d x 1 2 + d y 1 2 d l o n 1 2 + d l a t 1 2 = d x 2 2 + d y 2 2 d l o n 2 2 + d l a t 2 2 \frac{\sqrt{dx_1^2 + dy_1^2}}{\sqrt{dlon_1^2+dlat_1^2}} = \frac{\sqrt{dx_2^2 + dy_2^2}}{\sqrt{dlon_2^2+dlat_2^2}} dlon12+dlat12 dx12+dy12 =dlon22+dlat22 dx22+dy22
- 根据前文中提到的 两向量在不同的坐标系中的夹角是相同的
我们可得出以下四个式子:
① d x 1 k 1 = d x 2 k 3 ( 通 过 x 求 夹 角 c o s 值 ) ① \frac{dx_1}{k_1} = \frac{dx_2}{k_3} (通过x求夹角 cos 值) ①k1dx1=k3dx2(通过x求夹角cos值)
② d y 1 k 1 = d y 2 k 3 ( 通 过 y 求 夹 角 s i n 值 ) ② \frac{dy_1}{k_1} = \frac{dy_2}{k_3} (通过y求夹角 sin 值) ②k1dy1=k3dy2(通过y求夹角sin值)
③ d l o n 1 k 2 = d l o n 2 k 4 ( 通 过 经 度 求 夹 角 c o s 值 ) ③ \frac{dlon_1}{k_2} = \frac{dlon_2}{k_4} (通过经度求夹角 cos 值) ③k2dlon1=k4dlon2(通过经度求夹角cos值)
④ d l a t 1 k 2 = d l a t 2 k 4 ( 通 过 纬 度 求 夹 角 s i n 值 ) ④ \frac{dlat_1}{k_2} = \frac{dlat_2}{k_4} (通过纬度求夹角 sin 值) ④k2dlat1=k4dlat2(通过纬度求夹角sin值)
由 ① 乘以 ③ 可得:
⑤ d x 1 ⋅ d l o n 1 k 1 ⋅ k 2 = d x 2 ⋅ d l o n 2 k 3 ⋅ k 4 ⑤ \frac{dx_1 \cdot dlon_1 }{k1 \cdot k_2} = \frac{dx_2 \cdot dlon_2}{k_3 \cdot k_4} ⑤k1⋅k2dx1⋅dlon1=k3⋅k4dx2⋅dlon2
由 ② 乘以 ④ 可得:
⑥ d y 1 ⋅ d l a t 1 k 1 ⋅ k 2 = d y 2 ⋅ d l a t 2 k 3 ⋅ k 4 ⑥ \frac{dy_1 \cdot dlat_1 }{k1 \cdot k_2} = \frac{dy_2 \cdot dlat_2}{k_3 \cdot k_4} ⑥k1⋅k2dy1⋅dlat1=k3⋅k4dy2⋅dlat2
将 ⑤ 与 ⑥ 相加,即可得原文中提到的复合在一起的式子:
d x 1 ⋅ d l o n 1 + d y 1 ⋅ d l a t 1 k 1 ⋅ k 2 = d x 2 ⋅ d l o n 2 + d y 2 ⋅ d l a t 2 k 3 ⋅ k 4 \frac{dx_1 \cdot dlon_1 + dy_1 \cdot dlat_1 }{k1 \cdot k_2} = \frac{dx_2 \cdot dlon_2 + dy_2 \cdot dlat_2}{k_3 \cdot k_4} k1⋅k2dx1⋅dlon1+dy1⋅dlat1=k3⋅k4dx2⋅dlon2+dy2⋅dlat2
故最后的方程组为:
{ k 1 k 2 = k 3 k 4 d x 1 ⋅ d l o n 1 + d y 1 ⋅ d l a t 1 k 1 ⋅ k 2 = d x 2 ⋅ d l o n 2 + d y 2 ⋅ d l a t 2 k 3 ⋅ k 4 \begin{array}{l} \left\{\begin{matrix} \frac{k_1}{k_2} = \frac{k_3}{k_4} \\ \frac{dx_1 \cdot dlon_1 + dy_1 \cdot dlat_1 }{k1 \cdot k_2} = \frac{dx_2 \cdot dlon_2 + dy_2 \cdot dlat_2}{k_3 \cdot k_4} \end{matrix}\right. \end{array} {k2k1=k4k3k1⋅k2dx1⋅dlon1+dy1⋅dlat1=k3⋅k4dx2⋅dlon2+dy2⋅dlat2
我再贴张用LaTeX公式编辑器绘制出的大图:
通过解上面的方程组,我们就能得到未知的屏幕坐标或未知的地理坐标。
为什么呢?别看推导过程中代数符号(变量名)很多,其实不确定的值只有:
( x , y ) 和 ( l o n , l a t ) (x,y)和(lon,lat) (x,y)和(lon,lat)
故,接下来就简单了:
将 ( x , y ) (x,y) (x,y)带入方程组就可以得到 ( l o n , l a t ) (lon,lat) (lon,lat)
反过来,将 ( l o n , l a t ) (lon,lat) (lon,lat)带入方程组就可以得到 ( x , y ) (x,y) (x,y)
这里需要注意的是:
处于分母位置的 k 1 k_1 k1、 k 2 k_2 k2、 k 3 k_3 k3、 k 4 k_4 k4 都不能为零
转换为编程中的除零异常就是需要注意的是:
- 参考的两点不能完全相等
- 进行计算的 ( x , y ) (x,y) (x,y)或 ( l o n , l a t ) (lon,lat) (lon,lat)不能与第一个参考点相同
对于第二句话,由于类库使用者调用本函数时,不会注意传参顺序,故你可要求他要计算的点不应该为两个参考点中任意一个。
实际工程中,对于这个问题,我们判断一下 d x 1 , d y 1 dx_1,dy_1 dx1,dy1 ,即当前点是否和参考点重合,如果重合,直接返回参考点。
屏幕坐标转地理坐标(Java实现)
由于原文中已给出了详尽的C#
代码,这里我只给出自己的关于屏幕坐标转地理坐标的Java
实现。由于代码实现解方程组我还不熟悉,只能按照原有文章中的代码逻辑直接给出到大家,待后续有能力了,我会把变量都和代数中的符号保持一致。
1.首先定义包含 ( x , y ) (x,y) (x,y) 和 ( l o n , l a t ) (lon,lat) (lon,lat) 的数据存储的类
public class XYLonLatModle {private double x;private double y;private double longitude;private double latitude;public double getX() {return x;}public void setX(double x) {this.x = x;}public double getY() {return y;}public void setY(double y) {this.y = y;}public double getLongitude() {return longitude;}public void setLongitude(double longitude) {this.longitude = longitude;}public double getLatitude() {return latitude;}public void setLatitude(double latitude) {this.latitude = latitude;}public String getWgsString() {return latitude + "," + longitude;}
}
然后为了构建这个 XYLonLatModle
更加方便,我们再写一个 Builder
类。
public final class XYLonLatModleBuilder {private double x;private double y;private double longitude;private double latitude;private XYLonLatModleBuilder() {}public static XYLonLatModleBuilder aXYLonLatModle() {return new XYLonLatModleBuilder();}public XYLonLatModleBuilder withX(double x) {this.x = x;return this;}public XYLonLatModleBuilder withY(double y) {this.y = y;return this;}public XYLonLatModleBuilder withOriginalXY() {this.x = 0;this.y = 0;return this;}public XYLonLatModleBuilder withXyString(String xyString){String[] strings = xyString.split(",");this.x = Double.parseDouble(strings[0]);this.y = Double.parseDouble(strings[1]);return this;}public XYLonLatModleBuilder withLongitude(double longitude) {this.longitude = longitude;return this;}public XYLonLatModleBuilder withLatitude(double latitude) {this.latitude = latitude;return this;}public XYLonLatModleBuilder withLatitudeLongitudeString(String latLngString) {String[] strings = latLngString.split(",");this.latitude = Double.parseDouble(strings[0]);this.longitude = Double.parseDouble(strings[1]);return this;}public XYLonLatModle build() {XYLonLatModle xYLonLatModle = new XYLonLatModle();xYLonLatModle.setX(x);xYLonLatModle.setY(y);xYLonLatModle.setLongitude(longitude);xYLonLatModle.setLatitude(latitude);return xYLonLatModle;}
}
2.创建工具类根据两个参照点和当前的 ( x , y ) (x,y) (x,y) 计算 ( l o n , l a t ) (lon,lat) (lon,lat)
public class XYLongitudeLatitudeConvertUtil {public static double norm(double a, double b) {return Math.sqrt(a * a + b * b);}/*** x y 坐标转 经纬度** @param x* @param y* @param reference1* @param reference2* @return*/public static XYLonLatModle vectorMapXyToLatLng(double x, double y, XYLonLatModle reference1, XYLonLatModle reference2) {double x1 = reference1.getX();double y1 = reference1.getY();double lon1 = reference1.getLongitude();double lat1 = reference1.getLatitude();double x2 = reference2.getX();double y2 = reference2.getY();double lon2 = reference2.getLongitude();double lat2 = reference2.getLatitude();double lon_cos = Math.cos(lat2 * Math.PI / 180);double m = (lon2 - lon1) * lon_cos;double n = (lat2 - lat1);double dx1 = x2 - x1;double dy1 = y2 - y1;double dx2 = x - x1;double dy2 = y - y1;double a = (dx2 * dx2 + dy2 * dy2) * (m * m + n * n) / (dx1 * dx1 + dy1 * dy1);double norm = norm(m, n);double v = dx1 * dx2 + dy2 * dy1;double sqrt = Math.sqrt(a);double b = v * norm * sqrt / (norm(dx1, dy1) * norm(dx2, dy2));double c = Math.sqrt(b * b * n * n - (m * m + n * n) * (b * b - a * m * m));double q1 = (b * n + c) / (m * m + n * n);double q2 = (b * n - c) / (m * m + n * n);double p1 = (b - q1 * n) / m;double p2 = (b - q2 * n) / m;double lon_1 = p1 / lon_cos + lon1;double lat_1 = q1 + lat1;double lon_2 = p2 / lon_cos + lon1;double lat_2 = q2 + lat1;double judge1 = (lon_1 - lon1) * (lat2 - lat1) - (lat_1 - lat1) * (lon2 - lon1);double judge2 = (lon_2 - lon1) * (lat2 - lat1) - (lat_2 - lat1) * (lon2 - lon1);double judge = (x - x1) * (y2 - y1) - (y - y1) * (x2 - x1);double lon = 0;double lat = 0;if (judge * judge1 < 0) {lon = lon_1;lat = lat_1;} else {lon = lon_2;lat = lat_2;}XYLonLatModle xyLonLatModle = XYLonLatModleBuilder.aXYLonLatModle().withX(x).withY(y).withLongitude(lon).withLatitude(lat).build();return xyLonLatModle;}}
本方法未用到任何jar包依赖,直接使用的Java基本语法,故不需要给出import
最简易的调用就是用屏幕中的零点和一个较大的点来作参考:
XYLonLatModle originalPoint = XYLonLatModleBuilder.aXYLonLatModle().withOriginalXY().withLatitudeLongitudeString("20.156,52.369").build();
XYLonLatModle anotherPoint = XYLonLatModleBuilder.aXYLonLatModle().withXyString("5,5").withLatitudeLongitudeString("20.157,52.370").build();
XYLonLatModle xyLonLatModle = XYLongitudeLatitudeConvertUtil.vectorMapXyToLatLng(x, y, originalPoint, anotherPoint);
《地理坐标(经纬度坐标)和屏幕坐标(xy坐标)间的转换》的读后笔记相关推荐
- 游戏世界三维坐标转换为屏幕坐标原理分析:三角函数转换与矩阵变换
在3D游戏中获得游戏人物敌人坐标xyz后,并不能直接绘制到屏幕上,需要进行一系列的转换算法,目前主流的算法包括三角函数转换与矩阵变换,三角函数转换方法过时且繁琐,这里不推荐使用,本文主讲矩阵变换原理: ...
- cad零点坐标标注lisp_CAD XY坐标标注AUTO LISP程序
CAD X,Y 坐标坐标标注 AUTO LISP 程序 ;; (DEFUN IDPT(/ p px py pxx pyy) (DEFUN IDPT () (SETQ X T) (WHILE X (SE ...
- java地理坐标转屏幕_(转)经纬度坐标转换为屏幕坐标
经纬度坐标转换成屏幕坐标 地理坐标定义规则:X轴(代表经度)向右递增,Y轴(纬度)向上递增,就好比小学学过的平面坐标.向左.向下的规则.屏幕坐标定义规则:X轴向右递增,Y轴向下递增. 可以看出,地理坐 ...
- 地理坐标(经纬度)转换成投影坐标(XY坐标)
前言:限于需求,项目中所有涉及到经纬度的字段都要转换成XY坐标,面向度娘之后发现都没有可用的,琢磨了之后在以为大佬博客中发现了宝藏 使用工具:Proj4 Proj4是一个JavaScript类库,其主 ...
- 经纬度坐标转换为屏幕坐标
经纬度坐标转换成屏幕坐标 地理坐标定义规则:X轴(代表经度)向右递增,Y轴(纬度)向上递增,就好比小学学过的平面坐标.向左.向下的规则.屏幕坐标定义规则:X轴向右递增,Y轴向下递增. 可以看出,地理坐 ...
- UTM的XY坐标转换为WGS84经纬度坐标
本文是JAVA代码将UTM的XY坐标转换为WGS84的经纬度坐标.首先我们要知道几个参数. 当初设计的人一定会有以下参数提供,但是这些参数一般很少会去修改. 上图中的UTM Zone 50N代表中国东 ...
- 经纬度转换XY坐标,并计算距离
import pandas as pd import numpy as np from pyproj import Transformer import matplotlib.pyplot as pl ...
- 屏幕距离和坐便转换工具_地图经纬度坐标与屏幕坐标的转换(android版)
我们在开发GIS系统的时候,首先要解决的就是地图的可视化问题,这个问题的关键就在于如何把地图的坐标转换成屏幕坐标,然后才到渲染着色.标注等.以下以wgs84经纬度坐标为基准,介绍一下地图经纬度坐标与屏 ...
- ArcGIS如何将经纬度坐标显示转化为xy坐标显示
GIS中经纬度坐标显示如图: 视图-数据框属性-常规-显示(米) 点击确定,然后坐标显示就转换为xy坐标了 注意,以上设置只是设置了当前文档的坐标系统,并不是数据的坐标系 举个例子:我将2160这条等 ...
最新文章
- LeetCode: 111. Minimum Depth of Binary Tree
- KVM创建虚拟机(六)
- https下 http的会被阻塞 This request has been blocked; the content must be served over HTTPS.
- SAP Commerce Cloud Accelerator theme css 加载的问题和 multi step checkout
- 【转】C++学习四 冒泡排序法的一些改进
- 计算机改成服务器,旧电脑主机如何改成服务器
- 阿里风控大脑关于大数据应用的探索与实践
- 程序—java年月日转换
- 电商大促首焦背景素材|大火C4D元素
- [leetcode ]221. Maximal Square c语言
- java web 局部刷新页面_如何实现页面局部刷新(Java)
- matlab三维怎么转换二维,求助,二维图像如何绕轴旋转成为三维图像
- python人脸识别库_用python库face_recognition进行人脸识别
- 计算机毕业设计ssm图书管理系统
- sundancest201驱动_驱动支持列表
- android刷机教程 华为,华为Mate20X 刷机教程 华为Mate20X 强刷升级教程
- Ubuntu下安装UDK
- 中国医学史(第三章 中医药理论体系的初步形成)
- 蚂蚁金服×西安银行 | 西安银行手机银行App的智能升级之路 1
- windows linux 共存,Windows与Linux共存
热门文章
- win10强制关闭飞行模式_win10笔记本打开蓝牙功能的方法
- 计算机绝对引用公式是什么意思,excel绝对引用是什么?什么时候能用?怎么操作?...
- [zz CSDN]上班族饮食十大“夺命”恶习
- 图像语义分割——抠图勾画
- 一、HTML基础标签
- TCP切片和PSH理解
- 理解 HTTP 中的 multipart/form-data
- iOS: UIWebView 中不加载图片(即浏览器常见的无图模式)
- C语言PAT刷题 - 1009 说反话
- 找中医看病须五大注意(摘自网易)