为maven设置镜像解决国内下载依赖时超时的问题

国内访问repo1.maven.org访问不了,导致maven不能下载依赖,解决方法是自己设置maven的mirrors,就是设置镜像:

在~/.m2/目录下建立一个settings.xml文件,内容如下

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"  
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">  
  <mirrors>
  	<!-- mirror | Specifies a repository mirror site to use instead of a given 
  	repository. The repository that | this mirror serves has an ID that matches 
  	the mirrorOf element of this mirror. IDs are used | for inheritance and direct 
  	lookup purposes, and must be unique across the set of mirrors. | -->
  	<mirror>
	  	<id>id</id>
	  	<mirrorOf>central</mirrorOf>
	  	<name>name</name>
	  	<url>http://XXX</url>
  	</mirror>
  </mirrors>
</settings>

最好是公司或者自己设置的镜像地址,公网地址基本上不怎么靠谱,不是修改了包的内容打广告就是稳定性很差。

注意,如果由于更换代理导致问题,可以尝试删除~/.m2/repository 目录。

Tomcat 7.0 启用gzip压缩配置

打开 conf/server.xml 文件可以看到:

<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>

要使用 gzip 压缩功能,可以在 Connector 实例中加上如下属性:

  1. compression="on" 打开压缩功能
  2. compressionMinSize="2048" 启用压缩的输出内容大小,这里面默认为2KB
  3. noCompressionUserAgents="gozilla, traviata" 对于以下的浏览器,不启用压缩
  4. compressableMimeType="text/html,text/xml" 压缩类型

修改完成后

<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" compression="on" compressionMinSize="256" noCompressionUserAgents="gozilla,traviata" compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain" />

验证是否成功, 用 wireshark 抓包,可以看到如图所示:tomcat_gzip

VelocityTracker简单用法

VelocityTracker顾名思义即速度跟踪,在android中主要应用于touch event, VelocityTracker通过跟踪一连串事件实时计算出

当前的速度,这样的用法在android系统空间中随处可见,比如Gestures中的Fling, Scrolling等,下面简单介绍一下用法。

//获取一个VelocityTracker对象, 用完后记得回收
//回收后代表你不需要使用了,系统将此对象在此分配到其他请求者
static public VelocityTracker obtain();
public void recycle(); 
//计算当前速度, 其中units是单位表示, 1代表px/毫秒, 1000代表px/秒, ..
//maxVelocity此次计算速度你想要的最大值
public void computeCurrentVelocity(int units, float maxVelocity);
//经过一次computeCurrentVelocity后你就可以用一下几个方法获取此次计算的值
//id是touch event触摸点的ID, 来为多点触控标识,有这个标识在计算时可以忽略
//其他触点干扰,当然干扰肯定是有的
public float getXVelocity();
public float getYVelocity();
public float getXVelocity(int id);
public float getYVelocity(int id);

下面是我写的一个简单Demo:

package com.bxwu.demo.component.activity;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.ViewConfiguration;
import android.view.ViewGroup.LayoutParams;
import android.widget.TextView;

public class VelocityTrackerTest extends Activity {
    private TextView mInfo;

    private VelocityTracker mVelocityTracker;
    private int mMaxVelocity;

    private int mPointerId;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mInfo = new TextView(this);
        mInfo.setLines(4);
        mInfo.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
        mInfo.setTextColor(Color.WHITE);

        setContentView(mInfo);

        mMaxVelocity = ViewConfiguration.get(this).getMaximumFlingVelocity();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        final int action = event.getAction();
        acquireVelocityTracker(event);
        final VelocityTracker verTracker = mVelocityTracker;
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                //求第一个触点的id, 此时可能有多个触点,但至少一个
                mPointerId = event.getPointerId(0);
                break;

            case MotionEvent.ACTION_MOVE:
                //求伪瞬时速度
                verTracker.computeCurrentVelocity(1000, mMaxVelocity);
                final float velocityX = verTracker.getXVelocity(mPointerId);
                final float velocityY = verTracker.getYVelocity(mPointerId);
                recodeInfo(velocityX, velocityY);
                break;

            case MotionEvent.ACTION_UP:
                releaseVelocityTracker();
                break;

            case MotionEvent.ACTION_CANCEL:
                releaseVelocityTracker();
                break;

            default:
                break;
        }
        return super.onTouchEvent(event);
    }

    /**
     *
     * @param event 向VelocityTracker添加MotionEvent
     *
     * @see android.view.VelocityTracker#obtain()
     * @see android.view.VelocityTracker#addMovement(MotionEvent)
     */
    private void acquireVelocityTracker(final MotionEvent event) {
        if(null == mVelocityTracker) {
            mVelocityTracker = VelocityTracker.obtain();
        }
        mVelocityTracker.addMovement(event);
    }

    /**
     * 释放VelocityTracker
     *
     * @see android.view.VelocityTracker#clear()
     * @see android.view.VelocityTracker#recycle()
     */
    private void releaseVelocityTracker() {
        if(null != mVelocityTracker) {
            mVelocityTracker.clear();
            mVelocityTracker.recycle();
            mVelocityTracker = null;
        }
    }

    private static final String sFormatStr = "velocityX=%f\nvelocityY=%f";

    /**
     * 记录当前速度
     *
     * @param velocityX x轴速度
     * @param velocityY y轴速度
     */
    private void recodeInfo(final float velocityX, final float velocityY) {
        final String info = String.format(sFormatStr, velocityX, velocityY);
        mInfo.setText(info);
    }
}

代码很简单,我们可以求出move过程中的伪瞬时速度, 这样在做很多控件的时候都是可以用到的,比如系统Launcher的分页,

ScrollView滑动等, 可根据此时的速度来计算ACTION_UP后的减速运动等。实现一些非常棒的效果。

原始链接 http://blog.csdn.net/bingxianwu/article/details/7446799

判断一个点是否在指定区域内

在图像处理时,我们会经常需要判断一个点是否位于多边形区域内。比较好用的是射线法。

射线法

算法思想非常巧妙:从待判断的点向某一个方向引射线,计算和多边形交点的个数,如果个数是偶数或者0则点在多边形外,如果是奇数,则在多边形内,如下图:

1

这里有二种特殊情况:

1. 射线经过顶点:当射线经过顶点时,判断就会出现异常情况。

2. 点在边上:这种情况也不能用交点个数的奇偶性来判断了,要快速地判断这个点是否在边上。

C的实现如下:

#define MIN(x,y) (x < y ? x : y)
#define MAX(x,y) (x > y ? x : y)

typedef struct {
   double x,y;
} Point;

int InsidePolygon(Point *polygon,int N,Point p)
{
  int counter = 0;
  int i;
  double xinters;
  Point p1,p2;

  p1 = polygon[0];
  for (i=1;i<=N;i++) {
    p2 = polygon[i % N];
    if (p.y > MIN(p1.y,p2.y)) { //低
      if (p.y <= MAX(p1.y,p2.y)) { //高
        if (p.x <= MAX(p1.x,p2.x)) { //右
          if (p1.y != p2.y) { //简单忽略平行X轴这种情况
            xinters = (p.y-p1.y)*(p2.x-p1.x)/(p2.y-p1.y)+p1.x; //交叉点坐标 参考./media/point-and-polygon/xinters.jpg
            if (p1.x == p2.x || p.x <= xinters)
              counter++;
          }
        }
      }
    }
    p1 = p2;
  }

  if (counter % 2 == 0)
    return 0;
  else
    return 1;
}

再来个C#版的

public static bool Contains( Point[] points, Point p ) 
{
   bool result = false;
   for( int i = 0; i < points.Length - 1; i++ )
   {
      if( ( ( ( points[ i + 1 ].Y <= p.Y ) && ( p.Y < points[ i ].Y ) ) || ( ( points[ i ].Y <= p.Y ) && ( p.Y < points[ i + 1 ].Y ) ) ) && ( p.X < ( points[ i ].X - points[ i + 1 ].X ) * ( p.Y - points[ i + 1 ].Y ) / ( points[ i ].Y - points[ i + 1 ].Y ) + points[ i + 1 ].X ) )
      {
         result = !result;
      }
   }
   return result;
}

 

值得一提的是射线法对于带岛的多边形依然有效:

2

改进:传统的射线法一开始就直接计算点和多边形的交点个数,这样的话,会花费大量的时间来作拓扑关系的判断,我们可以首先计算出最小外包矩形,迅速排除不在矩形内部的点,然后再做上面的判断。

在Struts 2.0中国际化(i18n)

国际化Hello World

下面让我们看一个例子——HelloWorld。这个例子演示如何根据用户浏览器的设置输出相应的HelloWorld。

  1. 在src文件夹中加入struts.properties文件,内容如下:
    struts.custom.i18n.resources=globalMessages
  2. 在src文件夹中加入globalMessages_en_US.properties文件,内容如下:
    HelloWorld=Hello World!
  3. 在src文件夹中加入globalMessages_zh_CN.properties文件,内容如下:
    HelloWorld=你好,世界!
  4. 在WebContent文件夹下加入HelloWorl.jsp文件,内容如下:
    <%@ page  contentType="text/html; charset=UTF-8"%>
    <%@taglib prefix="lang" uri="/struts-tags"%>
    <html>
    <head>
    <title>Hello World</title>
    </head>
    <body>
    <h2><lang:text name="HelloWorld"/></h2>
    <h2><lang:property value="%{getText('HelloWorld')}"/></h2>
    </body>
    </html>

    具体的存放路径如图所示
    屏幕快照 2013-12-10 上午10.07.50

    发布运行应用程序,在浏览器地址栏中输入http://localhost:8080/Struts2_i18n/HelloWorld.jsp ,出现图1所示页面。

  5. 图1 中文输出
    图1 中文输出
  6. 将浏览器的默认语言改为“英语(美国)”,刷新页面,出现图2所示页面。
    r_imag2
    图2 英文输出

上面的例子的做法,与Struts 1.x的做法相似,似乎并不能体现Struts 2.0的优势。不过,我在上面的例子用了两种方法来显示国际化字符串,其输出是相同的。其实,这就是Struts 2.0的一个优势,因为它默认支持EL,所示我们可以用getText方法来简洁地取得国际化字符串。另外更普遍的情况——在使用UI表单标志时,getText可以用来设置label属性,例如:

<lang:textfield name="name" label="%{getText('UserName')}"/>

资源文件查找顺序

之所以说Struts 2.0的国际化更灵活是因为它可以能根据不同需要配置和获取资源(properties)文件。在Struts 2.0中有下面几种方法:

  1. 使用全局的资源文件,方法如上例所示。这适用于遍布于整个应用程序的国际化字符串,它们在不同的包(package)中被引用,如一些比较共用的出错提示;
  2. 使用包范围内的资源文件。做法是在包的根目录下新建名的package.properties和package_xx_XX.properties文件。这就适用于在包中不同类访问的资源;
  3. 使用Action范围的资源文件。做法为Action的包下新建文件名(除文件扩展名外)与Action类名同样的资源文件。它只能在该Action中访问。如此一来,我们就可以在不同的Action里使用相同的properties名表示不同的值。例如,在ActonOne中title为“动作一”,而同样用title在ActionTwo表示“动作二”,节省一些命名工夫;
  4. 使用<s:i18n>标志访问特定路径的properties文件。在使用这一方法时,请注意<s:i18n>标志的范围。在<s:i18n name="xxxxx">到</s:i18n>之间,所有的国际化字符串都会在名为xxxxx资源文件查找,如果找不到,Struts 2.0就会输出默认值(国际化字符串的名字)。

上面我列举了四种配置和访问资源的方法,它们的范围分别是从大到小,而Struts 2.0在查找国际化字符串所遵循的是特定的顺序,如图3所示:

o_Search
图3 资源文件查找顺序图

假设我们在某个ChildAction中调用了getText("user.title"),Struts 2.0的将会执行以下的操作:

  1. 查找ChildAction_xx_XX.properties文件或ChildAction.properties;
  2. 查找ChildAction实现的接口,查找与接口同名的资源文件MyInterface.properties;
  3. 查找ChildAction的父类ParentAction的properties文件,文件名为ParentAction.properties;
  4. 判断当前ChildAction是否实现接口ModelDriven。如果是,调用getModel()获得对象,查找与其同名的资源文件;
  5. 查找当前包下的package.properties文件;
  6. 查找当前包的父包,直到最顶层包;
  7. 在值栈(Value Stack)中,查找名为user的属性,转到user类型同名的资源文件,查找键为title的资源;
  8. 查找在struts.properties配置的默认的资源文件,参考例1;
  9. 输出user.title。

参数化国际化字符串

许多情况下,我们都需要在动行时(runtime)为国际化字符插入一些参数,例如在输入验证提示信息的时候。在Struts 2.0中,我们通过以下两种方法做到这点:

  1. 在资源文件的国际化字符串中使用OGNL,格式为${表达式},例如:
    validation.require=${getText(fileName)} is required

    使用java.text.MessageFormat中的字符串格式,格式为{ 参数序号(从0开始), 格式类形(number | date | time | choice), 格式样式},例如:

  2. validation.between=Date must between {0, date, short} and {1, date, short}

    在显示这些国际化字符时,同样有两种方法设置参数的值:

  1. 使用标志的value0、value1...valueN的属性,如:
    <lang:text name="validation.required" value0="User Name"/>
  2. 使用param子元素,这些param将按先后顺序,代入到国际化字符串的参数中,例如:
    <lang:text name="validation.required">
    <lang:param value="User Name"/>

让用户方便地选择语言

开发国际化的应用程序时,有一个功能是必不可少的——让用户快捷地选择或切换语言。在Struts 2.0中,通过ActionContext.getContext().setLocale(Locale arg)可以设置用户的默认语言。不过,由于这是一个比较普遍的应用场景(Scenario),所以Struts 2.0为您提供了一个名i18n的拦截器(Interceptor),并在默认情况下将其注册到拦截器链(Interceptor chain)中。它的原理为在执行Action方法前,i18n拦截器查找请求中的一个名为"request_locale"的参数。如果其存在,拦截器就将其作为参数实例化Locale对象,并将其设为用户默认的区域(Locale),最后,将此Locale对象保存在session的名为“WW_TRANS_I18N_LOCALE”的属性中。

下面,我将提供一完整示例演示它的使用方法。

package tutorial;

import java.util.Hashtable;
import java.util.Locale;
import java.util.Map;

publicclass Locales {
    public Map<String, Locale> getLocales() {
        Map<String, Locale> locales =new Hashtable<String, Locale>(2);
        locales.put("American English", Locale.US);
        locales.put("Simplified Chinese", Locale.CHINA);
        return locales;
    }
}

tutorial/Locales.java

<%@taglib prefix="lang" uri="/struts-tags"%>
<script type="text/javascript">
<!--
function langSelecter_onChanged() {
document.langForm.submit();
}
//-->
</script>
<lang:set name="SESSION_LOCALE" value="#session['WW_TRANS_I18N_LOCALE']"/>
<lang:bean id="locales" name="tutorial.Locales"/>
<form action="<lang:url includeParams="get" encode="true"/>" name="langForm"
style="background-color: powderblue; padding-top: 4px; padding-bottom: 4px;">
Language: <lang:select label="Language"
list="#locales.locales" listKey="value"    listValue="key"
value="#SESSION_LOCALE == null ? locale : #SESSION_LOCALE"
name="request_locale" id="langSelecter"
onchange="langSelecter_onChanged()" theme="simple"/>
</form>

LangSelector.jsp

上述代码的原理为,LangSelector.jsp先实例化一个Locales对象,并把对象的Map类型的属性locales赋予下拉列表(select) 。如此一来,下拉列表就获得可用语言的列表。大家看到LangSelector有<s:form>标志和一段Javascript脚本,它们的作用就是在用户在下拉列表中选择了后,提交包含“reqeust_locale”变量的表单到Action。在打开页面时,为了下拉列表的选中的当前区域,我们需要到session取得当前区域(键为“WW_TRANS_I18N_LOCALE”的属性),而该属性在没有设置语言前是为空的,所以通过值栈中locale属性来取得当前区域(用户浏览器所设置的语言)。

你可以把LangSelector.jsp作为一个控件使用,方法是在JSP页面中把它包含进来,代码如下所示:

<lang:include value="/LangSelector.jsp"/>

在例1中的HellloWorld.jsp中<body>后加入上述代码,并在struts.xml中新建Action,代码如下:

<action name="HelloWorld">
<result>/HelloWorld.jsp</result>
</action>

或者,如果你多个JSP需要实现上述功能,你可以使用下面的通用配置,而不是为每一个JSP页面都新建一个Action。

<action name="*">
<result>/{1}.jsp</result>
</action>

分布运行程序,在浏览器的地址栏中输入http://localhost:8080/Struts2_i18n/HelloWorld.action,出现图4所示页面:

r_imag3
图3 HelloWorld.action

在下拉列表中,选择“American English”,出现图5所示页面:
r_imag4
图4 HelloWorld.action

可能大家会问为什么一定要通过Action来访问页面呢?

你可以试一下不用Action而直接用JSP的地址来访问页面,结果会是无论你在下拉列表中选择什么,语言都不会改变。这表示不能正常运行的。其原因为如果直接使用JSP访问页面,Struts 2.0在web.xml的配置的过滤器(Filter)就不会工作,所以拦截器链也不会工作。

参考 http://www.blogjava.net/max/archive/2006/11/01/78536.html

Mac 10.9 执行 brew update 报错 error: pathspec 'master' did not match any file(s) known to git.

想在Mac 上面安装 tomcat 结果总是提示失败,报错 404 ,应该是软件源过期了,因此执行

sudo brew update

可是悲剧的是却报告如下错误

$ sudo brew update

error: pathspec 'master' did not match any file(s) known to git.
Error: Failure while executing: git checkout -q master

网上搜寻了一下,找到解决方案

sudo rm -rf /usr/local/.git

然后再执行更新就正常了。

PostgreSql 安装配置 PostGIS

1.安装PostGIS插件

sudo apt-get install PostGIS
sudo apt-get install postgresql-9.3-postgis

2.开启PostgreSql对于PostGIS 的支持,在psql 或者 PgAdmin 中执行命令

-- Enable PostGIS (includes raster)
CREATE EXTENSION postgis;
-- Enable Topology
CREATE EXTENSION postgis_topology;
-- fuzzy matching needed for Tiger
CREATE EXTENSION fuzzystrmatch;
-- Enable US Tiger Geocoder
CREATE EXTENSION postgis_tiger_geocoder;

3.测试例子

-- Create table with spatial column
CREATE TABLE mytable ( 
  id SERIAL PRIMARY KEY,
  geom GEOMETRY(Point, 26910),
  name VARCHAR(128)
); 

-- Add a spatial index
CREATE INDEX mytable_gix
  ON mytable 
  USING GIST (geom); 

-- Add a point
INSERT INTO mytable (geom) VALUES (
  ST_GeomFromText('POINT(0 0)', 26910)
);

-- Query for nearby points
SELECT id, name
FROM mytable
WHERE ST_DWithin(
  geom, 
  ST_GeomFromText('POINT(0 0)', 26910),
  1000
);

PostGIS 快速入门

PostGIS 是 PostgreSQL 关系数据库的空间操作扩展。它为 PostgreSQL 提供了存储、查询和修改空间关系的能力。本文中 ‘PostgreSQL’ 指代基本的关系数据库功能,而 ‘PostGIS’ 指代扩展的空间操作特性。

  • 客户端-服务器构架

PostgreSQL 同众多数据库产品一样,采用客户端-服务器构架。客户端向服务器发出请求并得到响应。这种机制同浏览器从网络服务器获取网页类似。在 PostgreSQL 中,请求以 SQL 语言发出,而响应多为从数据库提取的表单。

客户端与服务器可以部署在同一台设备上,即 PostgreSQL 可以在单一的计算机上使用。借由系统内部的 ‘loopback’ 通信机制,数据库系统可以进行私密通讯。除非专门配置,外界是不能访问这些信息的。

本位介绍三种客户端:命令行, Quantum GISpgAdmin 图形化数据库客户端。

  • 创造具有空间信息处理能力的数据库

命令行客户端在终端模拟器(Terminal Emulator)中运行。在 Applications 菜单的 Accessories 中打开一个终端模拟器,将显示一个 Unix 风格的命令行界面。输入:

psql -V

回车确认,将显示 PostgreSQL 版本号。

一个 PostgreSQL 服务器中,可以将不同的任务组织到不同的数据库。每个数据库独立运作,拥有专门的表单、显示、用户等。访问 PostgreSQL 数据库时将指定一个数据库。

服务器上数据库列表通过以下命令查询:

psql -l

输出将罗列 Live 上配置的几个数据库。这里演示新建一个。

PostgreSQL 使用 createdb 工具创建数据库。这里建立的数据库应带有 PostGIS 的扩展功能,因此需要指定相应的模板。这里将新建数据库称为 demo 。命令为:

createdb -T template_postgis demo

现在执行 psql -l 应当可以看到 demo 数据库。

也可以使用 SQL 语言创建 PostGIS 数据库。首先使用 dropdb 命令删除之前创建的数据库,然后使用 psql 命令开启 SQL 命令解析器:

dropdb demo
psql -d postgres

这样就连接到了一个通用的系统数据库 postgres 。输入 SQL 命令建立新数据库:

postgres=# CREATE DATABASE demo TEMPLATE=template_postgis;

现在可以转换连接到新建的数据库。若重新连接时可以使用 psql -d demo 命令。但在 psql 系统内部也可以使用以下命令:

postgres=# \c demo

一个信息页面将显示当前已连接 demo 数据库。输入 \dt 列出当前数据库内的表单,输出如下:

demo=# \dt
             List of relations
 Schema |       Name       | Type  | Owner
--------+------------------+-------+-------
 public | geometry_columns | table | user
 public | spatial_ref_sys  | table | user
(2 rows)

这两个表格是 PostGIS 默认的。其中 spatial_ref_sys 存储着合法的空间坐标系统。利用 SQL 查询查看:

demo=# SELECT srid,auth_name,proj4text FROM spatial_ref_sys LIMIT 10;

 srid | auth_name |          proj4text
------+-----------+--------------------------------------
 3819 | EPSG      | +proj=longlat +ellps=bessel +towgs...
 3821 | EPSG      | +proj=longlat +ellps=aust_SA +no_d...
 3824 | EPSG      | +proj=longlat +ellps=GRS80 +towgs8...
 3889 | EPSG      | +proj=longlat +ellps=GRS80 +towgs8...
 3906 | EPSG      | +proj=longlat +ellps=bessel +no_de...
 4001 | EPSG      | +proj=longlat +ellps=airy +no_defs...
 4002 | EPSG      | +proj=longlat +a=6377340.189 +b=63...
 4003 | EPSG      | +proj=longlat +ellps=aust_SA +no_d...
 4004 | EPSG      | +proj=longlat +ellps=bessel +no_de...
 4005 | EPSG      | +proj=longlat +a=6377492.018 +b=63...
(10 rows)

以上显示确认了该数据库已经建立空间操作功能。数据库中的 geometry_columns 用于记录那些表格是有空间信息的。

  • 手工建立空间数据表格

空间数据库已经建立,现在可以建立具有空间信息的表格。

首先建立一个常规的表格存储有关城市(cities)的信息。这个表格有两栏,一个是 ID 编号,一个是城市名:

demo=# CREATE TABLE cities ( id int4, name varchar(50) );

现在添加一个空间栏用于存储城市的位置。习惯上这个栏目叫做 the_geom 。它记录了数据为什么类型(点、线、面)、有几维(这里是二维)以及空间坐标系统。此处使用 EPSG:4326 坐标系统:

demo=# SELECT AddGeometryColumn ('cities', 'the_geom', 4326, 'POINT', 2);

完成后,查询 cities 表单应当显示这个新栏目。同时页面将显示当前表达没有记录(0 rows)。

demo=# SELECT * from cities;
 id | name | the_geom
----+------+----------
(0 rows)

为添加记录,需要使用 SQL 命令。对于空间栏,使用 PostGIS 的 ST_GeomFromText 可以将文本转化为坐标与参考系号的记录:

demo=# INSERT INTO cities (id, the_geom, name) VALUES (1,ST_GeomFromText('POINT(-0.1257 51.508)',4326),'London, England');
demo=# INSERT INTO cities (id, the_geom, name) VALUES (2,ST_GeomFromText('POINT(-81.233 42.983)',4326),'London, Ontario');
demo=# INSERT INTO cities (id, the_geom, name) VALUES (3,ST_GeomFromText('POINT(27.91162491 -33.01529)',4326),'East London,SA');

当然,这样的输入方式难以操作。其它方式可以更快的输入数据。就目前来说,表格内已经有了一些城市数据,可以先进行查询等操作。

  • 简单查询

标准的 SQL 操作都可以用于 PostGIS 表单:

demo=# SELECT * FROM cities;
 id |      name       |                      the_geom
----+-----------------+----------------------------------------------------
  1 | London, England | 0101000020E6100000BBB88D06F016C0BF1B2FDD2406C14940
  2 | London, Ontario | 0101000020E6100000F4FDD478E94E54C0E7FBA9F1D27D4540
  3 | East London,SA  | 0101000020E610000040AB064060E93B4059FAD005F58140C0
(3 rows)

这里的坐标是无法阅读的 16 进制格式。要以 WKT 文本显示,使用 ST_AsText(the_geom) 或 ST_AsEwkt(the_geom) 函数。也可以使用 ST_X(the_geom) 和 ST_Y(the_geom) 显示一个维度的坐标:

demo=# SELECT id, ST_AsText(the_geom), ST_AsEwkt(the_geom), ST_X(the_geom), ST_Y(the_geom) FROM cities;
 id |          st_astext           |               st_asewkt                |    st_x     |   st_y
----+------------------------------+----------------------------------------+-------------+-----------
  1 | POINT(-0.1257 51.508)        | SRID=4326;POINT(-0.1257 51.508)        |     -0.1257 |    51.508
  2 | POINT(-81.233 42.983)        | SRID=4326;POINT(-81.233 42.983)        |     -81.233 |    42.983
  3 | POINT(27.91162491 -33.01529) | SRID=4326;POINT(27.91162491 -33.01529) | 27.91162491 | -33.01529
(3 rows)
  • 空间查询:

PostGIS 为 PostgreSQL 扩展了许多空间操作功能。以上已经涉及了转换空间坐标格式的 ST_GeomFromText 。多数空间操作以 ST(spatial type)开头,在 PostGIS 文档相应章节有罗列。这里回答一个具体的问题:以米为单位并假设地球是完美椭球,上面三个城市相互的距离是多少?

demo=# SELECT p1.name,p2.name,ST_Distance_Sphere(p1.the_geom,p2.the_geom) FROM cities AS p1, cities AS p2 WHERE p1.id > p2.id;
      name       |      name       | st_distance_sphere
-----------------+-----------------+--------------------
 London, Ontario | London, England |   5875766.85191657
 East London,SA  | London, England |   9789646.96784908
 East London,SA  | London, Ontario |   13892160.9525778
 (3 rows)

输出显示了距离数据。注意 ‘WHERE’ 部分防止了输出城市到自身的距离(0)或者两个城市不同排列的距离数据(London, England 到 London, Ontario 和 London, Ontario 到 London, England 的距离是一样的)。尝试取消 ‘WHERE’ 并查看结果。

这里采取不同的椭球参数(椭球体名、半主轴长、扁率)计算:

demo=# SELECT p1.name,p2.name,ST_Distance_Spheroid(
        p1.the_geom,p2.the_geom, 'SPHEROID["GRS_1980",6378137,298.257222]'
        )
       FROM cities AS p1, cities AS p2 WHERE p1.id > p2.id;
      name       |      name       | st_distance_spheroid
-----------------+-----------------+----------------------
 London, Ontario | London, England |     5892413.63776489
 East London,SA  | London, England |     9756842.65711931
 East London,SA  | London, Ontario |     13884149.4140698
(3 rows)
  • 制图

以 PostGIS 数据制图需要相应的客户端支持。包括 Quantum GIS、gvSIG、uDig 在内的多种客户端均可以。以下使用 Quantum GIS:

从 Desktop GIS 菜单启动 Quantum GIS 并在其 layer 菜单选择 Add PostGIS layers 。连接到 Natural Earth PostGIS 数据库的参数在 Connections 下拉菜单中有。这里可以定义和储存其它的配置。点击 Edit 可以查看具体参数。点击 Connect 连接:

postgis_addlayers  系统将显示所有空间信息表供选择:

postgis_listtables  选择 lakes 湖泊表单并点击底部的 Add 添加。顶部的 Load 可以载入新的数据库连接配置。数据将被导入:

postgis_lakesmap  界面上显示出湖泊的分布。QGIS 并不理解湖泊一词的含义,也许不会自动使用蓝色。请查看其手册了解如何设置。这里缩放到加拿大一处著名的湖泊群。

  • 自动创建空间数据表单

OSGeo Live 的多数桌面 GIS 系统都可以将 shp 等文件导入数据库。这里依然使用 QGIS 演示。

QGIS 中导入 shp 可以使用 PostGIS Manager 插件。在 Plugins 菜单选择 Fetch Plugins 导入最新的官方插件列表(需要网络连接)。找到 PostGIS Manager 点击 Install plugin 安装。

postgis_getmanager  完成后,在 Plugin 菜单点击 PostGIS Manager 启动。也可以点击工具栏上大象与地球的图标。

该插件将连接 Natural Earth 数据库。若提示输入密码,留空即可。在开启的界面中,选择表单可以显示相应的信息。预览(Preview)选项卡可以显示地图预览。这里选择了 populated places 图层并缩放到一个小岛:

postgis_managerpreview  接下来使用 PostGIS Manager 将 shp 导入数据库。这里使用 R 统计扩展包含的 North Carolina sudden infant death syndrome (SIDS) 数据:

Data 菜单选择 Load data from shapefile 选项。点击 ... 选中 R maptools 中的 sids.shp

postgis_browsedata  直接点击 Load 即可:

postgis_importsids

数据将被导入 PostGIS 。关闭 PostGIS Manager 回到主界面。

使用 ‘Add PostGIS Layer’ 导入 SIDS 数据。略加调整,得到被卡洛莱娜州新生儿猝死率分布图:

postgis_sidsmap

  • pgAdmin III

通过 Databases 菜单下的 pgAdmin III 可以进行非空间操作。该客户端是 PostgreSQL 的官方产品,使用 SQL 语句操作。

postgis_adminscreen1 postgis_adminscreen2

进一步尝试

可以尝试其它一些操作:

  1. 尝试 st_buffer(the_geom)st_transform(the_geom,25831)x(the_geom) 等空间操作,相关文档位于 http://postgis.org/documentation/
  2. 在命令行使用 pgsql2shp 将表单导出到 shp 。
  3. 在命令行使用 ogr2ogr 导入导出数据。

其它信息

以下网站包含了有关 PostGIS 的大量信息:

PostGIS 主页

PostGIS 文档

Ubuntu 13.10 PostgreSQL 9.3 快速入门

  • 启动
sudo /etc/init.d/postgresql start
  • 停止
sudo /etc/init.d/postgresql stop
  • 设置密码

安装完毕,我们需要更改postgres用户的密码,否则我们就没法使用这个数据库服务器。以postgres这个系统用户的身份运行psql命令,在终端中输入如下:

sudo su postgres -c psql template1

这时候会出现新的提示符,输入下面两个命令,用新密码替换 <***password***>:

ALTER USER postgres WITH PASSWORD ' <***password***> ';
  • 设置 postgres 用户的密码
sudo passwd postgres

而后输入自己的密码

  • 创建数据库

创建第一个数据库,我们把它命名为"mydb",先输入:

su postgres

转为 postgres 用户登陆后,执行

createdb mydb
  • 使用pgAdmin III图形界面客户端

要了解PostgreSQL能干些什么,你首先要学会使用一个图形界面的客户端,在终端中输入:

pgadmin3

你现在停留在pgAdmin III的主界面,点击 "添加数据库连接" 按钮(在左上方)。弹出一个新的对话框,输入地址127.0.0.1,服务器描述,默认数据库"mydb" 和你的密码。

注意,如果pgadmin3报告

“发生了一个错误:
Error connecting to the server: 无法联接到服务器: 连接被拒绝
服务器是否在主机 "127.0.0.1" 上运行并且准备接受在端口
5432 上的 TCP/IP 联接?”

则原因为

原来postgres8.4.4之后的版本的监听端口竟然改为5433了,而pgadmin中默认端口还是5432

通过这个图形界面,你可以新建数据库,表和其他对象;查询数据库,添加数据,执行SQL语句等。 用pgAdmin 3连接

500px-Pgadminpostgresql

  • 管理用户和权限

PostgreSQL没有一个简单的管理用户的方法 ,首先你必需编辑/etc/postgres/pg_hba.conf 并修改它的默认配置(默认配置的安全性非常高),你希望 postgres 来管理它的用户(和系统用户无关),你需要添加如下几行:

<-------------------------------------------
# TYPE DATABASE USER IP-ADDRESS IP-MASK METHOD
# rezo local
host all all 10.0.0.0 255.255.255.0 password
<-------------------------------------------

它的意思是通过你的本地网络(10.0.0.0/24要替换为你的本地网络 !), postgres用户可以以传统的”用户名+密码“的方式连接到数据库。

创建一个数据库,并创建一个对该数据库拥有所有权限的用户,可以使用如下命令:

sudo su postgres -c createuser -D -A -P myuser
sudo su postgres -c createdb -O myuser mydb

第一个命令是创建一个新用户,这个用户没有创建数据库的权限(-D),没有新建用户的权限(-A)。创建用户时会提示你输入密码。第二个命令是创建一个数据库'mydb ,以 'myuser' 作为它的所有者。