图7-4用优化的“序列化”工具在Java中对几何体进行读写

下面的这个例子,首先用结果集的getObject()方法,把各行的几何体对象提取为STRUCT类型,然后使用JGeometry的静态方法load()把它转换成JGeometry对象。

STRUCT dbObject = (STRUCT) rs.getObject(1);

JGeometry geom = JGeometry.load(dbObject);

要使用优化的反序列化工具(unpickler),首先使用结果集的getBytes( )方法提取几何体到一个字节数组中。然后再次使用JGeometry的静态方法load()把它转换成JGeometry对象。

byte[] image = rs. getBytes (1);

JGeometry geom = JGeometry.load(image);

2.检查几何体

你现在可以用多个get()方法从几何对象中提取信息。表7-2中总结了主要的方法。在表7-3中附加的is()方法对几何体的特性进行了细化。

表7-2JGeometry中主要的get()方法

方法返 回 信 息

getType()几何体类型(1表示点,2表示线,依次类推)

getDimensions()维度

getSRID()空间参考系ID

getNumPoints()几何体中的点数

getPoint()点对象的坐标(如果几何体是点)

getFirstPoint()几何体中的第一点

getLastPoint()几何体中的最后一点

getMBR()几何体的MBR

getElemInfo()SDO_ELEM_INFO数组的内容

getOrdinatesArray()SDO_ORDINATES数组的内容

getLabelPoint()返回SDO_POINT结构的坐标。当用来填充线或多边形几何体时,这通常被用来当标记点

getJavaPoint()对一个单点对象来说,以java.awt.geom.Point2D对象的形式返回点坐标

getJavaPoints()对多点对象来说,返回一个java.awt.geom.Point2D对象数组

getElements()得到一个JGeometry对象数组,每个对象都表示几何体的一个元素

getElementAt()以JGeometry格式提取几何体的一个元素

createShape()把几何体转换成java.awt.Shape对象,为绘制和使用java.awt包中的工具做准备

表7-3主要的JGeometry is()方法

方法返 回 信 息

isPoint()是不是点

isOrientedPoint()是不是有向点

isCircle()是不是圆

isGeodeticMBR()是不是大地测量学的MBR

isMultiPoint()是不是多点

isRectangle()是不是矩形

hasCircularArcs()几何体中是否包含弧

isLRSGeometry()是不是一个线性参照的几何体

表7-2中的两个方法(getElements()和getElementAt())可以对复杂几何体的结构进行检查:你可以提取独立的元素作为单独的JGeometry对象。第一个方法返回所有元素到独立的JGeometry对象数组中。第二个方法返回一个指定元素,通过其在几何体中的位置来标识。

警告:

对element术语的理解应参见OGC Simple Features for SQL规范。例如,一个有孔多边形被看作是一个单元素,尽管它由多个环(在Oracle概念中,每个都是一个单元素)组成。在第5章中讨论的验证函数(VALIDATE_GEOMETRY_WITH_CONTEXT()和EXTRACT())表现出同样的方式。这就意味着getElements()方法不允许你从一个有孔多边形中提取孔。

警告:

元素的编号方式是从1开始的,而不是0。

3.创建几何体

向数据库中写入几何体(用INSERT或UPDATE语句)要求先创建一个新的JGeometry对象,并用JGeometry.store()方法把它转换成STRUCT。然后把STRUCT传递给INSERT或UPDATE语句。同load()方法一样,也可以使用速度更快的空间序列化工具。图7-3和7-4展示了这两个方法。

下面是这两个方法的例子。首先用JGeometry的静态方法store()把它转换为STRUCT,然后用setObject()方法把它插入到准备好的SQL语句中。

STRUCT dbObject = JGeometry.store (geom, dbConnection);

stmt.setObject (1,dbObject);

使用优化的序列化工具除了与store()方法的参数顺序相反以外,其他的都一样:先是定义数据库连接对象,然后是创建JGeometry对象。

STRUCT dbObject = JGeometry.store (dbConnection, geom);

stmt.setObject (1,dbObject);

有两种方法可以构造新的JGeometry对象。一种是使用表7-4中的构造函数。另一种方法是用静态的方法来创建不同的几何体。表7-5列出了这些方法。

表7-4JGeometry转换器

构 造 函 数目的

JGeometry (double x, double y, int srid)构造点

JGeometry (double x, double y, double z, int srid)构造三维点

JGeometry (double minX, double minY, double maxX,

double maxY, int srid)创建矩形

JGeometry (int gtype, int srid, int[] elemInfo, double[] ordinates)构造一般几何体

表7-5静态JGeometry创建方法

创 建 方 法目的

createPoint(double[] coord, int dim, int srid)创建点

createLinearLineString(double[] coords, int dim, int srid)创建简单线串

createLinearPolygon(double[] coords, int dim, int srid)创建简单多边形

createMultiPoint(java.lang.Object[] coords, int dim, int srid)创建多重点对象

createLinearMultiLineString(java.lang.Object[] coords, int dim, int srid)创建多重线串对象

createLinearPolygon(java.lang.Object[] coords, int dim, int srid)创建多重多边形

createCircle(double x1, double y1, double x2, double y2, double x3, double y3, int srid)用圆上三点创建圆

createCircle(double x, double y, double radius, int srid)用中心和半径创建圆

4.修改存在的几何体

JGeometry类没有提供任何用于修改几何体的方法。例如,没有方法用来从一个线上删除或添加一点。为了执行那些更新,你需要用某个方法,如getOrdinatesArray(),来提取点序列,然后更新由此产生的Java数组,最后用其结果来创建一个新的JGeometry对象。

像先前讨论的那样把修改后的几何体写入到数据库中:用store()方法把JGeometry对象转换为STRUCT,然后把STRUCT传给SQL中的INSERT或UPDATE语句。

5.处理几何体

Java API也提供了大量的用于对几何体执行各种转换的方法。表7-6中列出了主要的方法。它们以JGeometry对象作为输入而以生成的新几何体作为输出。注意,这些函数大部分都由数据库提供,并通过PL/SQL来对其进行调用,这一内容将在第9章中详述。

表7-6几何体处理函数

方法目的

buffer(double bufferWidth)在几何体周围形成一个缓冲区

simplify(double threshold)简化几何体

densifyArcs(double arc_tolerance)在几何体中增加所有弧的密度

clone()复制一个几何体

affineTransforms(...)基于提供的参数(平移、缩放、旋转、切变、反射)在输入几何体上应用仿射变换

projectToLTP(double smax, double flat)把一个几何体从经度/纬度投影到一个切面上

projectFromLTP()把一个几何体从一个本地切面投影到经度/纬度上

表7-7总结了API提供的一些辅助方法。这些函数都不涉及JGeometry对象(除了equals),用来辅助处理一定的任务。

equals()函数用来比较两个JGeometry对象,判断它们是否相同。然而,这种比较是基于几何体的内部编码的:如果两个几何体的所有点的坐标都相同且顺序相同,那么就认为这两个几何体相同。该方法不真正进行涉及容差的几何体的比较。

表7-7几何体辅助函数

方法目的

equals()判断两个几何体是否相同

computeArc(double x1, double y1, double x2,

double y2, double x3, double y3)从三个坐标点来计算这个弧的中心、半径和角度

linearizeArc(double x1, double y1, double

x2,double y2, double x3, double y3)把一个弧转换成一组二维线段

reFormulateArc(double[] d)通过重新计算角度重构一条弧

expandCircle(double x1, double y1, double x2,

double y2, double x3, double y3)通过把圆转换成一组二维线段来实现对其的线性化

monoMeasure(double[] coords, int dim )判断一条线是否有变长或缩短的方法

7.2.2使用3D几何体:J3D_Geometry类

Oracle Database 11g的一个主要的新功能就是它能够对复杂的3D对象(表面和立方体)进行建模。新的J3D_Geometry类能够帮助你操作那些结构。注意,它是JGeometry的子类,所以到目前为止,你已经了解的所有方法都是适用的。

像处理JGeometry一样,从数据库中读取J3D_Geometry对象,然后由JGeometry对象构造一个J3D_Geometry对象。例如:

byte[] image = rs. getBytes (1);

JGeometry geom = JGeometry.load(image);

J3D_Geometry geom3D = new J3D_Geometry (

geom.getType(), geom.getSRID(),

geom.getElemInfo(), geom.getOrdinatesArray()

);

仅通过使用规则的JGeometry.store()函数向数据库中写入J3D_Geometry对象:

STRUCT dbObject = JGeometry.store (dbConnection, geom3d);

stmt.setObject (1,dbObject);

与JGeometry相似,它提供给你大量的方法用来对几何体进行不同的操作。表7-8总结了这些方法。

表7-83D几何体处理函数

方法目的

anyInteract(J3D_Geometry A, double tolerance)判断两个三维几何体是否相交

extrusion(JGeometry polygon, double grdHeight, double height, Connection conn, boolean cond, double tolerance)通过对一个二维多边形进行拉伸返回一个三维几何体

closestPoints(J3D_Geometry A, double tolerance)计算出两个三维几何体中离得最近的点

getMBH(J3D_Geometry geom)对一个三维几何体[3]返回一个三维的边界框

validate(double tolerance)验证一个三维图像的有效性

area(double tolerance)计算一个面或立方体中一面的面积

length(int count_shared_edges, double tolerance)计算三维形状的长度

volume(double tolerance)计算三维立方体的体积

distance(J3D_Geometry A, double tolerance)计算两个三维几何体之间的距离

7.2.3从3D几何体中提取元素:ElementExtractor类

3D对象可能是复杂的。立方体尤其符合这种情况。一个复杂的立方体由多个简单的立方体组成。这些简单的立方体又由表面组成,它们中的某些几何体构成了立方体中的孔。表面本身由各种元素构成,而这些元素又由环组成。

ElementExtractor类使得对复杂对象的检查和独立组件的提取变得容易,如组成立方体的一个或多个表面。注意,你也可以对一些规则的二维几何体使用提取器。例如,在一个复杂的多边形中,它对提取一个环的线性等高线是很有用的。

可以通过两种方式使用提取器:一个是提取指定的元素,另一个是对所有有效的元素进行迭代。

提示:

ElementExtractor类并不只局限于3D几何体,对2D图形也适用。但是因为其输入必须是J3D_Geometry对象,所以首先要把JGeometry对象转换成一个J3D_Geometry对象。

1.提取独立元素

你需要做的就是调用静态的getElementByLabel()方法,传入一个用于唯一标记待提取几何体元素的标签。这个标签是一个由逗号分隔的ID号码字符串,该号码指定了待返回的几何体的子集。根据需要可以对以下列出的元素进行指定(对在最后一个指定的元素前的任何一个null元素,为其输入一个逗号)。

●点ID

●边ID

●环ID

●多边形ID

●表面ID

●立方体ID

●多重立方体ID

这些ID号是每个元素在每一级上的序列号。序列号从1开始:在多重多边形中第一个多边形是多边形1。它的环从1到N编号。第二个多边形是多边形2,其中的环仍从1到N编号。

例如,下面的代码将从简单立方体的表面2中返回3号多边形:

J3D_Geometry ring=ElementExtractor.getElementByLabel(solid,"0,0,0,3,2");

注意,当有错误发生时,J3D_Geometry中的validate()方法将返回这样一个标记。你可以通过向ElementExtractor.getElementByLabel()传递这个标记来分离发生错误的元素。

2.对元素进行迭代

创建一个ElementExtractor对象,向它传递你的查询的参数。这实际上将创建一个在一定详细程度上初始化的迭代器。接着,你可以通过其nextElement()方法来逐个提取对象的组件。然后还可以用另一个ElementExtractor对象进一步地检查第一次循环所得到的每个元素。

表7-9详细介绍了创建一个ElementExtractor对象所要用到的参数。这些参数控制提取器的行为方式。

表7-9ElementExtractor的参数

参数目的

geometry待分析的3D几何体

firstElement开始提取的位置,在几何体的SDO_ELEM_INFO

数组中被定义为偏移量。默认值为0

extractionLevel这个参数决定迭代器处理几何体中元素的方法。

请参见“提取级别”一节获取详细信息

allow_comp_sub_elements指定为true(默认值)或false。在MULTICOMP_TOSIMPLE提取级别上,用户可以通过把这个参数设置为FALSE,从多个或复合几何体中直接提取简单几何体。默认值为TRUE,这意味着用户将先从多几何体中提取复合几何体

3.提取级别

extractionLevel参数控制提取器的操作方式。以下面的值对其进行指定。名称为在类中所定义的常量。

●Level 0 = MULTICOMP_TOSIMPLE:它返回一个在多重几何体中的连续元素。例如,它将返回多立方体中的每个立方体或多重多边形中的每个多边形。可以把它想象成对元素的水平扫描。

●Level 1 = INNER_OUTER:如果存在,它将返回内部/外部元素。对于多边形,它先返回外环,接着返回内环。

●Level 2 = LOWER_LEVEL:它返回子元素;也就是,它返回下一个层次中的元素(例如,对立方体而言它的下一级是表面,而对于多边形而言是边,以此类推)。

让我们来看看一个有多个孔的多重多边形的简单例子。我们首先用MULTICOMP_TOSIMPLE对其进行充分的扫描。这将把这个多重多边形分解为单个简单的多边形。

下一步是从这些多边形中提取环。首先要用INNER_OUTER扫描由第一步返回的多边形。

对于无孔的多边形,结果不会变。但是对于那些有孔的多边形,你首先得到的是表示外环的多边形,然后是一个或多个表示内环的多边形。

最后,为了进一步分解几何体,用LOWER_LEVEL对每一个环进行扫描。这种扫描将把每个环分解成一个边集——有两个顶点的简单的线串集。

下面是用提取器把一个多重几何体分解为元素的一个例子:

// Create new extractor

ElementExtractor e = new ElementExtractor (

geom3d, 0, ElementExtractor.MULTICOMP_TOSIMPLE);

// Geometry to receive extracted element(s)

J3D_Geometry g;

// Used to receive the type of element (1=outer, 2=inner)

int is_a_hole[] = {0};

// Extract the elements

while ((g = e.nextElement(is_a_hole)) != null) {

// Process extracted element

}

注意,nextElement()需要一个输出参数来表示其输出的元素是外部元素还是内部元素。这个参数必须以int[]的形式定义,其第一个元素被设置成1(表示外部元素)或2(表示内部元素)。这仅适用于LOWER_LEVEL扫描,但是所有的情况中都需要输出参数。

4.递归分解

你不需要对extractionLevel参数进行指定。如果忽略了,提取器将自动选择最合适的级别用作对几何体的分析。这使得它很容易在其成分上对几何体进行递归地分解,直到独立的线段。这将在下面的例子中得到展示:

void decomposeGeometry (J3D_Geometry geom, int level, int seq)

throws Exception

{

System.out.println ("Level: "+ level+" Sequence: "+seq);

if ((geom.getType() == geom.GTYPE_CURVE) ||

(geom.getType() == geom.GTYPE_POINT))

return;

MyElementExtractor e = new MyElementExtractor (geom);

int i = 0;

J3D_Geometry g;

int h[] = {0};

while ((g = e.nextElement(h)) != null) {

decomposeGeometry (g, level + 1, i+1);

i++;

}

}

7.2.4使用标准的格式:WKT、WKB和GML

在第5章中我们讨论了能够在SDO_GEOMETRY类型和开放地理信息系统联盟(OGC)定义的标准格式之间进行转换的PL/SQL函数和方法。OGC的标准格式有:WKT(熟知文本)、WKB(熟知二进制)和GML(地理标识语言)。我们将对怎样在Java中执行这些转换做简要解释。

对这些格式进行操作的类都在oracle.spatial.util包中。SdoExport.java和SdoImport.java程序(可以从Apress站点下载)对WKT、WKB和GML格式的读写提供了功能齐全的例子。

1.对WKT的读写

WKT格式是对几何体编码的一个结构化文本格式。它最初被设计为在不同环境间交换几何体的一种标准方法。点在WKT中可以被编码为:

POINT(-111.870478 33.685992)

一个简单多边形可以编码为:

POLYGON ((-119.308006 37.778061,..., -119.308006 37.778061))

我们将使用oracle.spatial.util包中WKT类的fromJGeometry()方法将JGeometry对象转换为WKT格式。注意,这个方法将生成一个字节数组,在将其写入到文件前,需要把它转换成一个字符串。如下所示:

// Create a WKT processor

WKT wkt = new WKT();

...

// Convert the geometry to WKT

String s = new String(wkt.fromJGeometry(geom));

也可以用WKT类中的toJGeometry方法把WKT字符串转回为JGeometry对象。这个方法的输入也是一个字节数组。过程如下所示:

// Create a WKT processor

WKT wkt = new WKT();

...

// Convert the WKT to geometry

JGeometry geom = wkt.toJGeometry(s.getBytes());

警告:

WKT和WKB格式没有提供任何的机制用来表示几何投影;也就是说,在将几何体转换成另一种格式时,这类信息将丢失。如果想保留这些信息,需要单独对其进行处理,同时用setSRID()方法把它回添到几何体中。

2.对WKB的读写

顾名思义,WKB编码就是把几何体以二进制的方式编码,是一种比WKT更紧凑的格式。它的使用方法与前面的处理相似。WKB类中的fromJGeometry()方法也产生一个字节数组,你可以把该数组写到文件中。我们将向你展示怎样将其写入java DataOutputStream(在例子中称为ds)中,以便以便携的方式写入原始Java数据类型。

首先把JGeometry转换为WKB。这将产生一个字节数组。然后把字节数组的大小和几何体的SRID写入输出流。最后以适当的方式写入字节数组。

// Create a WKB processor

WKB wkb = new WKB(ByteOrder.BIG_ENDIAN);

...

// Convert JGeometry to WKB

byte[] b = wkb.fromJGeometry(geom);

// First write the number of bytes in the array

ds.writeInt(b.length);

// Then write the SRID of the geometry

ds.writeInt(geom.getSRID());

// Then write the binary array

ds.write(b);

注意,ByteOrder.BIG_ENDIAN参数表明要使用的二进制编码的类型:大尾段(big endian)或小尾段(litle endian)。默认生成大尾段编码。你需要使其与用来处理WKB工具所接受的编码相适应。注意,其中选择的编码方法本身是在二进制结果的第一个字节被标记的。

用WKB类中的toJGeometry()方法可以把WKB转换成JGeometry对象。这个方法仍用字节数组作为输入。下面的例子展示了这个过程。假设我们从先前的文件中读取数据,首先读取WKB的长度,然后读取几何体的SRID。接下来读取重建WKB所需的字节数。最后把WKB转换为JGeometry对象并用setSRID方法把SRID写回。

// Create a WKB processor

WKB wkb = new WKB();

...

// Read the size of the byte array

int n = ds.readInt();

// Read the SRID of the geometry

int srid = ds.readInt();

// Read the byte array that contains the WKB

byte[] b = new byte[n];

int l = ds.read (b, 0, n);

// Convert to JGeometry

geom = wkb.toJGeometry(b);

// Add the SRID

geom.setSRID(srid);

我们不需要指定将要使用的二进制编码的格式(大尾段或小尾段),因为toJGeometry()方法能够自动对编码进行识别并可以对两者进行透明的处理。

3.对GML的读写

WKT和WKB有许多限制:它们只支持简单2D的形状,而不支持任何3D的形状,以及弧或圆。另外,它们也无法指定对几何体的投影。GML(地理标识语言)则是一个强有力的解决方案,它对地理信息进行XML编码。

为了对GML进行读写,我们将展示怎样使用表7-10中总结的4个类及其方法。存在多个类的原因是GML标准在不断更新中。现在有两个主要的版本:GML2和GML3,其中GML3提供对3D(表面和立方体)和其他高级工具的支持。

表7-10对GML进行处理的类和方法

GML版本写GML读GML

GML2GML2.to_GMLGeometry()GML.fromNodeToGeometry()

GML3GML3.to_GML3Geometry()GML3g.fromNodeToGeometry()

其中GML3是GML2的父集,所以任意由GML2编码的几何体都可以被GML3读取。反之则不成立。

把JGeometry对象转换成GML格式很容易,如下所示:

//Create a GML2 Processor

GML2 gml = new GML2();

---

String s = gml.to_GMLGeometry(geom);

如你所见,to_GMLGeometry()返回一个可以直接写出的字符串。你也可以把结果(一个XML串)包含在其他XML文档中。上面的例子使用了GML2。而对GML3的使用,只要使用合适的类和方法就可以了。

把GML字符串转换成JGeometry对象就比较麻烦了。转换方法(GML.fromNode ToGeometry()和GML3g.fromNodeToGeometry())不支持GML字符串直接作为输入,但是支持解析文档。所以在使用这些方法之前,你自己必须首先对GML字符串进行解析。下面的例子展示了这个过程:

// Create a GML3 Processor

GML3 gml = new GML3g();

...

// Read GML string from input stream

String s = ds.readLine();

// Setup an XML DOM parser

DOMParser parser = new DOMParser();

// Parse the XML string

parser.parse(new StringReader(s));

// Get the parsed document

Document document = parser.getDocument();

// Get the top level node of the document

Node node = document.getDocumentElement();

// Convert to geometry

geom = gml.fromNodeToGeometry(node);

注意到,这里使用了GML3处理器。要是使用GML2处理器,只需把GML3g转换为GML。

警告:

确保不要弄混在GML处理中包含的类的名称。

7.2.5使用ESRI shapefile

ESRI shapefile格式是进行地理数据传输的流行格式。在第5章中,我们曾用了一个简单的命令行工具对shapefile进行转换并把它们加载到空间表中。现在我们要展示的是怎样在Java中对其进行读写。为此,我们将要用到oracle.spatial.util包中的一些类。

如果你仅需把ESRI shapefile加载到数据库表中,那么oracle.spatial.util就能够满足你的需求。调用SampleShapefileToJGeomFeature类并向它传递合适的参数。如果你不了解这些参数,可以不包含任何参数,该类将告诉你这些参数的详情。下面是把shp_cities shapefile内容加载到us_cities表中的例子:

C:\>java oracle.spatial.util.SampleShapefileToJGeomFeature -h 127.0.0.1 -p 1521

-s orcl111 -u spatial -d spatial -t us_cities -f shp_cities -r 8307

host: 127.0.0.1

port: 1521

sid: orcl111

db_username: spatial

db_password: spatial

db_tablename: us_cities

shapefile_name: shp_cities

SRID: 8307

Connecting to Oracle10g using...

127.0.0.1,1521,orcl111, spatial, spatial, us_cities, shp_cities, null, 8307

Dropping old table...

Creating new table...

Converting record #10 of 195

Converting record #20 of 195

Converting record #30 of 195

Converting record #40 of 195

Converting record #50 of 195

Converting record #60 of 195

Converting record #70 of 195

Converting record #80 of 195

Converting record #90 of 195

Converting record #100 of 195

Converting record #110 of 195

Converting record #120 of 195

Converting record #130 of 195

Converting record #140 of 195

Converting record #150 of 195

Converting record #160 of 195

Converting record #170 of 195

Converting record #180 of 195

Converting record #190 of 195

195 record(s) converted.

Done.

该类将创建表、加载该表并在USER_SDO_GEOM_METADATA中插入合适的元数据。

1.对shapefile的简单说明

shapefile名字会让人产生误解。每个shapefile至少由3个文件构成,它们的文件名都相同,只是扩展名互不相同。例如,在前面例子中的shp_cities shapefile实际上是下面文件的集合:

●shp_cities.shp:这个文件中保存了对实际几何体的定义。

●shp_cities.shx:在形状上的空间索引。

●shp_cities.dbf:一个dBASEⅣ文件,包含每个几何体的属性。

有些shapefile中也带有其他一些文件,如shp_cities.prj或shp_cities.sbn。这些都会被Oracle Spatial Java类所忽略。

在为shapefile命名的时候不要包含.shp扩展名。所有组成同一个shapefile的文件都应该被存储在同一个目录下。

2.在程序中加载shapefile

oracle.spatial.util包中包含了3个可以用来在你的程序中读取和加载shapefile的类。表7-11是对它们的总结。

表7-11Shapefile处理类

类名称目的

ShapefileReaderJGeom提供函数,用来从shapefile中读取形状(几何体)并把它们转换成JGeometry对象

DBFReaderJGeom提供函数,用来从DBF文件中读取属性并获取该属性的名称和类型

ShapefileFeatureJGeom使用两个读取类提供高端函数,用来创建数据库表并从shapefile中对其进行加载

下面的例子展示了怎样用shapefile处理类把shapefile加载器简单地合并到你的应用中。首先是打开输入文件并设置辅助类。要注意的是,shapeFileName中包含的是没有扩展名的shapefile名称。

// Open SHP and DBF files

ShapefileReaderJGeom shpr = new ShapefileReaderJGeom(shapeFileName);

DBFReaderJGeom dbfr = new DBFReaderJGeom(shapeFileName);

ShapefileFeatureJGeom sf = new ShapefileFeatureJGeom();

然后提取shapefile的维度,也就是在文件中的所有维度上的所有几何体坐标的最大值和最小值。

// Get shapefile bounds and dimension

double minX = shpr.getMinX();

double maxX = shpr.getMaxX();

double minY = shpr.getMinY();

double maxY = shpr.getMaxY();

double minZ = shpr.getMinZ();

double maxZ = shpr.getMaxZ();

double minM = shpr.getMinMeasure();

double maxM = shpr.getMaxMeasure();

int shpDims = shpr.getShpDims(shpFileType, maxM);

现在可以构建空间元数据了。getDimArray()方法将根据shapefile中数据的限制和维度来生成合适的元数据定义。注意,在使用该方法时的一个特殊现象:X和Y维上的最大值和最小值必须以字符串的形式传递;Z和M维上的最大值和最小值以数字的形式传递。

// Construct the spatial metadata

String dimArray = sf.getDimArray(

shpDims, String.valueOf(tolerance),

String.valueOf(minX), String.valueOf(maxX),

String.valueOf(minY), String.valueOf(maxY),

minZ, maxZ, minM, maxM

);

接下来可以在数据库中创建表了。该方法会先删除已经存在的表,然后用合适的Oracle数据类型(与DBF文件中的属性类型相匹配)创建一个新表。它也会向USER_SDO_ GEOM_METADATA中插入空间元数据。指定SDO_GEOMETRY列的名称(geoColumn)。你也可以有选择地指定某个标识列(idColumn)的名称。该列将在加载的过程中被自动填充序列号。

// Create table before loading

sf.prepareTableForData(

dbConnection, dbfr, tableName, geoColumn, idColumn,

srid, dimArray

);

现在你可以从shapefile中把数据加载到刚刚创建的数据库表中了。insertFeatures方法有很多参数:标识列名(idColumn)、起始数据值(firstId)、提交的频率(commitFrequency)和载入期间打印进度消息的频率(printFrequency)。

// Load the features

sf.insertFeatures(dbConnection, dbfr, shpr, tableName,

idColumn, firstId,

commitFrequency, printFrequency, srid,

dimArray

);

最后,记得关闭输入文件:

// Close input file

shpr.closeShapefile();

dbfr.closeDBF();

3.构建你自己的加载器

如果想要更大的灵活性,如选择要加载的属性、对其重命名或在加载前对几何体进行一些处理,就可以使用ShapefileReaderJGeom和DBFReaderJGeom类中较低层次的方法。表7-12和表7-13对其作了总结。

表7-12ShapefileReaderJGeom方法

方法目的

getMinX()为x维返回最小值

getMaxX()为x维返回最大值

getMinY()为y维返回最小值

getMaxY()为y维返回最大值

getMinZ()为z维返回最小值

getMaxZ()为z维返回最大值

getMinMeasure()为m维返回最小值

getMaxMeasure()为m维返回最大值

getShpFileType()返回该shapefile中包含的几何体的类型:

点为1,线为3,多边形为5

getShpDims()返回几何体的维度

numRecords()返回shapefile中记录的数目

getGeometryBytes(int nth)从shapefile中以字节数组的形式提取第n个几何体

getGeometry(byte[] recBuffer, int srid) ()把一个几何体从形状二进制编码转换为JGeometry对象

closeShapefile()关闭shapefile

表7-13DBFReaderJGeom方法

方法目的

numRecords()返回DBF文件中记录的数目。

这应该与shapefile中的记录数相匹配

numFields()返回DBF文件中属性的个数(与列数相等)

getFieldName(int nth)以字符串的形式返回第n个域的名称

getFieldType(int nth)以单独字符编码的形式返回第n个域的类型

getFieldLength(int nth)返回第n个域的长度(在文件中占据的字节数)

getRecord(int nth)以字节数组的形式返回文件中的第n个记录

getFieldData(int nth, byte[] rec)从二进制记录中提取第n个域的值

closeDBF()关闭DBF文件

使用这些方法你可以从DBF文件中提取属性的名称、类型和属性大小。根据获得的信息,你在创建数据表时就有了充分的灵活性。以下展示了如何把DBF数据类型等价地映射到Oracle中。

int numFields = dbfr.numFields();

String[] fieldName = new String[numFields];

byte[] fieldType = new byte[numFields];

int[] fieldLength = new int[numFields];

String[] oracleType = new String[numFields];

for (int i=0; i

fieldName[i] = dbfr.getFieldName(i);

fieldType[i] = dbfr.getFieldType(i);

fieldLength[i] = dbfr.getFieldLength(i);

switch (fieldType[i]) {

case 'C': // Character

oracleType[i] = "VARCHAR2(" + fieldLength[i] + ")";

break;

case 'L': // Logical

oracleType[i] = "CHAR(1)";

break;

case 'D': // Date

oracleType[i] = "DATE";

break;

case 'I': // Integer

case 'F': // Float

case 'N': // Numeric

oracleType[i] = "NUMBER";

break;

default:

throw new RuntimeException("Unsupported DBF field type " + fieldType[i]);

}

}

你可以很容易地创建相应的表。仅向CREATE TABLE语句添加属性名称就可以实现。

String createTableSql = "CREATE TABLE " + tableName + "(";

for (int i=0; i

createTableSql = createTableSql + fieldName[i] + " " + oracleType[i] + ",";

createTableSql = createTableSql + geoColumn + " SDO_GEOMETRY)";

最后,通过循环向数据库中读取和插入数据,以便对SHP和DBF记录逐个地进行获取和处理。我们假设你构建并准备了相应的INSERT语句,每个待填充的列都有一个绑定变量。

for (int rowNumber = 0; rowNumber < numRows; rowNumber++)

{

// Extract attributes values from current DBF record

byte[] a = dbfr.getRecord (rowNumber);

for (int i = 0; i< dbfr.numFields(); i++) {

stmt.setString (i+1,dbfr.getFieldData(i, a));

}

// Extract geometry from current SHP record

byte[] s = shpr.getGeometryBytes (rowNumber);

JGeometry geom = ShapefileReaderJGeom.getGeometry (s, srid);

// Convert JGeometry object into database object

Struct dbObject = JGeometry.store (dbConnection, geom);

stmt.setObject (numFields+1, dbObject);

// Insert row into the database table

stmt.execute();

}

java jgeometry_7.2 在Java中操作几何体相关推荐

  1. java有什么字符串_Java 中操作字符串都有哪些类?它们之间有什么区别

    1. String.StringBuffer.StringBuilder 原文出自<编写高质量代码:改善 Java 程序的 151 个建议> CharSequence 接口有三个实现类与字 ...

  2. 每个java程序都至少有一个线程给主线程,java程序在主线程中判断各个子线程状态的操作,该如何解决...

    java程序在主线程中判断各个子线程状态的操作 每个子线程在队列为空时会wait等待其他线程添加新url到队列,到最后所有子线程都取不到url时也会都wait住,要在主线程中判断如果所有的子线程都是w ...

  3. java 8 Stream中操作类型和peek的使用

    文章目录 简介 中间操作和终止操作 peek 结论 java 8 Stream中操作类型和peek的使用 简介 java 8 stream作为流式操作有两种操作类型,中间操作和终止操作.这两种有什么区 ...

  4. java将map根据key分组_Java将List中的实体类按照某个字段进行分组并存放至Map中操作代码...

    本篇文章小编给大家分享一下Java将List中的实体类按照某个字段进行分组并存放至Map中操作代码,文章代码介绍的很详细,小编觉得挺不错的,现在分享给大家供大家参考,有需要的小伙伴们可以来看看. 1. ...

  5. java与es8实战之五:SpringBoot应用中操作es8(带安全检查:https、账号密码、API Key)

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本篇是<java与es8实战>系 ...

  6. java与es8实战之四:SpringBoot应用中操作es8(无安全检查)

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本篇是<java与es8实战>系 ...

  7. Java程序中操作Word表格

    本文将对如何在Java程序中操作Word表格作进一步介绍.操作要点包括 如何在Word中创建嵌套表格. 对已有表格添加行或者列 复制已有表格中的指定行或者列 对跨页的表格可设置是否禁止跨页断行 创建表 ...

  8. Java IO练习--在程序中写一个“HelloJavaWorld你好世界“输出到操作系统文件Hello.txt文件中

    package com.kj.test;import cn.hutool.core.io.IoUtil;import java.io.File; import java.io.FileOutputSt ...

  9. 在Java中操作MySQL(JDBC)

    准备工作 idea mysql 官方的 jdbc 驱动 先在 idea 中建立一个新的 java 工程 直到这一步之前,一直按下一步就行了 把名字改改直接 finish 在这个工程下面建立一个名字为 ...

最新文章

  1. 安卓手机也能跑YOLOv5了!
  2. HTML 表格垂直对齐方式
  3. C# : 调用C++动态库(dll)
  4. http、https、密码学基础、GET和POST区别
  5. HTML5 保存画布
  6. sql server 2008新特性:资源调控器
  7. python二维向量运算_python中二维数组的Elementwise与or或运算
  8. mysql两表查询单个_对两个表进行单个MySQL选择查询是可能的吗?
  9. php中的date()函数d y m l等字母的表示方法
  10. 图像处理基础(8):图像的灰度直方图、直方图均衡化、直方图规定化(匹配)
  11. golang 提示:can‘t resolve file
  12. 探讨【IGE】的源代码【二】。
  13. 计算机跨专业考会计专硕,二本二战三跨如何考上985会计专硕之数学篇
  14. Android开发中验证码的生成
  15. 将keras的模型封装成可转换为tensorlow的.pb格式,并生成.pbtxt文件
  16. Debian 8 安装BtSync
  17. 计算机管理系统在哪里,Win7系统realtek高清晰音频管理器在哪里打开?
  18. Autodesk 3ds Max 特定轴旋转
  19. 提取pdb氨基酸序列
  20. Jenkins | 搭建你第一个Jenkins应用

热门文章

  1. 鼓励孩子最常用的101句赞赏语
  2. 桌面计算机密码应由哪项组成,福师《计算机应用基础》在线作业一
  3. python操作execl——收藏必备
  4. java如何设置classpath_java的环境变量classpath该怎么设置呢?
  5. 如何手动生成ASH报告
  6. 奇虎360市值达搜狐两倍
  7. php中 hint,已经定义hint=0为啥还要if(hint=0)
  8. 寻侠家将选择,后期家将选择经验谈
  9. 足球胜平负数据这样分析竞猜准确率超高,你敢相信吗?
  10. 贪婪算法(贪心算法)