Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
000f7bb6
提交
000f7bb6
authored
9月 09, 2018
作者:
Evgenij Ryazanov
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Cache dimension system and envelope in ValueGeometry
上级
2ef109c3
显示空白字符变更
内嵌
并排
正在显示
10 个修改的文件
包含
181 行增加
和
45 行删除
+181
-45
AggregateDataEnvelope.java
...in/org/h2/expression/aggregate/AggregateDataEnvelope.java
+1
-1
MVSpatialIndex.java
h2/src/main/org/h2/mvstore/db/MVSpatialIndex.java
+2
-4
EWKBUtils.java
h2/src/main/org/h2/util/geometry/EWKBUtils.java
+22
-7
EWKTUtils.java
h2/src/main/org/h2/util/geometry/EWKTUtils.java
+30
-4
GeometryUtils.java
h2/src/main/org/h2/util/geometry/GeometryUtils.java
+1
-1
JTSUtils.java
h2/src/main/org/h2/util/geometry/JTSUtils.java
+32
-5
Value.java
h2/src/main/org/h2/value/Value.java
+1
-1
ValueGeometry.java
h2/src/main/org/h2/value/ValueGeometry.java
+88
-18
TestGeometryUtils.java
h2/src/test/org/h2/test/unit/TestGeometryUtils.java
+3
-3
dictionary.txt
h2/src/tools/org/h2/build/doc/dictionary.txt
+1
-1
没有找到文件。
h2/src/main/org/h2/expression/aggregate/AggregateDataEnvelope.java
浏览文件 @
000f7bb6
...
...
@@ -69,7 +69,7 @@ class AggregateDataEnvelope extends AggregateData {
if
(
envelope
==
null
)
{
return
ValueNull
.
INSTANCE
;
}
return
ValueGeometry
.
get
(
GeometryUtils
.
envelope2wkb
(
envelope
)
);
return
ValueGeometry
.
fromEnvelope
(
envelope
);
}
}
h2/src/main/org/h2/mvstore/db/MVSpatialIndex.java
浏览文件 @
000f7bb6
...
...
@@ -34,7 +34,6 @@ import org.h2.result.SearchRow;
import
org.h2.result.SortOrder
;
import
org.h2.table.IndexColumn
;
import
org.h2.table.TableFilter
;
import
org.h2.util.geometry.GeometryUtils
;
import
org.h2.value.Value
;
import
org.h2.value.ValueGeometry
;
import
org.h2.value.ValueLong
;
...
...
@@ -268,7 +267,7 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex {
bmaxyf
=
maxyf
;
}
}
return
ValueGeometry
.
get
(
GeometryUtils
.
envelope2wkb
(
new
double
[]
{
bminxf
,
bmaxxf
,
bminyf
,
bmaxyf
})
);
return
ValueGeometry
.
fromEnvelope
(
new
double
[]
{
bminxf
,
bmaxxf
,
bminyf
,
bmaxyf
}
);
}
return
ValueNull
.
INSTANCE
;
}
...
...
@@ -514,8 +513,7 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex {
}
Value
getBounds
()
{
return
hasBounds
?
ValueGeometry
.
get
(
GeometryUtils
.
envelope2wkb
(
new
double
[]
{
bminxd
,
bmaxxd
,
bminyd
,
bmaxyd
}))
return
hasBounds
?
ValueGeometry
.
fromEnvelope
(
new
double
[]
{
bminxd
,
bmaxxd
,
bminyd
,
bmaxyd
})
:
ValueNull
.
INSTANCE
;
}
...
...
h2/src/main/org/h2/util/geometry/EWKBUtils.java
浏览文件 @
000f7bb6
...
...
@@ -237,11 +237,26 @@ public final class EWKBUtils {
public
static
byte
[]
ewkb2ewkb
(
byte
[]
ewkb
)
{
// Determine dimension system first
DimensionSystemTarget
dimensionTarget
=
new
DimensionSystemTarget
();
parseE
KW
B
(
ewkb
,
dimensionTarget
);
parseE
WK
B
(
ewkb
,
dimensionTarget
);
// Write an EWKB
return
ewkb2ewkb
(
ewkb
,
dimensionTarget
.
getDimensionSystem
());
}
/**
* Converts any supported EWKB to EWKB representation that is used by this
* class. Reduces dimension system to minimal possible and uses EWKB flags
* for dimension system indication. May also perform other changes.
*
* @param ewkb
* source EWKB
* @param dimension
* dimension system
* @return canonical EWKB, may be the same as the source
*/
public
static
byte
[]
ewkb2ewkb
(
byte
[]
ewkb
,
int
dimensionSystem
)
{
ByteArrayOutputStream
output
=
new
ByteArrayOutputStream
();
EWKBTarget
target
=
new
EWKBTarget
(
output
,
dimension
Target
.
getDimensionSystem
()
);
parseE
KW
B
(
ewkb
,
target
);
EWKBTarget
target
=
new
EWKBTarget
(
output
,
dimension
System
);
parseE
WK
B
(
ewkb
,
target
);
return
output
.
toByteArray
();
}
...
...
@@ -253,8 +268,8 @@ public final class EWKBUtils {
* @param target
* output target
*/
public
static
void
parseE
KW
B
(
byte
[]
ewkb
,
Target
target
)
{
parseE
KW
B
(
new
EWKBSource
(
ewkb
),
target
,
0
,
0
);
public
static
void
parseE
WK
B
(
byte
[]
ewkb
,
Target
target
)
{
parseE
WK
B
(
new
EWKBSource
(
ewkb
),
target
,
0
,
0
);
}
/**
...
...
@@ -270,7 +285,7 @@ public final class EWKBUtils {
* SRID of a parent geometry collection, or any value for the
* root geometry (will be determined from the EWKB instead)
*/
private
static
void
parseE
KW
B
(
EWKBSource
source
,
Target
target
,
int
parentType
,
int
parentSrid
)
{
private
static
void
parseE
WK
B
(
EWKBSource
source
,
Target
target
,
int
parentType
,
int
parentSrid
)
{
try
{
// Read byte order of a next geometry
switch
(
source
.
readByte
())
{
...
...
@@ -374,7 +389,7 @@ public final class EWKBUtils {
target
.
startCollection
(
type
,
srid
,
numItems
);
for
(
int
i
=
0
;
i
<
numItems
;
i
++)
{
Target
innerTarget
=
target
.
startCollectionItem
(
i
,
numItems
);
parseE
KW
B
(
source
,
innerTarget
,
type
,
srid
);
parseE
WK
B
(
source
,
innerTarget
,
type
,
srid
);
target
.
endCollectionItem
(
innerTarget
,
i
,
numItems
);
}
target
.
endCollection
(
type
);
...
...
h2/src/main/org/h2/util/geometry/EWKTUtils.java
浏览文件 @
000f7bb6
...
...
@@ -442,11 +442,24 @@ public final class EWKTUtils {
public
static
String
ewkb2ewkt
(
byte
[]
ewkb
)
{
// Determine dimension system first
DimensionSystemTarget
dimensionTarget
=
new
DimensionSystemTarget
();
EWKBUtils
.
parseE
KW
B
(
ewkb
,
dimensionTarget
);
EWKBUtils
.
parseE
WK
B
(
ewkb
,
dimensionTarget
);
// Write an EWKT
return
ewkb2ewkt
(
ewkb
,
dimensionTarget
.
getDimensionSystem
());
}
/**
* Converts EWKB to EWKT.
*
* @param ewkb
* source EWKB
* @param dimension
* dimension system
* @return EWKT representation
*/
public
static
String
ewkb2ewkt
(
byte
[]
ewkb
,
int
dimensionSystem
)
{
StringBuilder
output
=
new
StringBuilder
();
EWKTTarget
target
=
new
EWKTTarget
(
output
,
dimension
Target
.
getDimensionSystem
()
);
EWKBUtils
.
parseE
KW
B
(
ewkb
,
target
);
EWKTTarget
target
=
new
EWKTTarget
(
output
,
dimension
System
);
EWKBUtils
.
parseE
WK
B
(
ewkb
,
target
);
return
output
.
toString
();
}
...
...
@@ -462,8 +475,21 @@ public final class EWKTUtils {
DimensionSystemTarget
dimensionTarget
=
new
DimensionSystemTarget
();
parseEWKT
(
ewkt
,
dimensionTarget
);
// Write an EWKB
return
ewkt2ewkb
(
ewkt
,
dimensionTarget
.
getDimensionSystem
());
}
/**
* Converts EWKT to EWKB.
*
* @param ewkt
* source EWKT
* @param dimension
* dimension system
* @return EWKB representation
*/
public
static
byte
[]
ewkt2ewkb
(
String
ewkt
,
int
dimensionSystem
)
{
ByteArrayOutputStream
output
=
new
ByteArrayOutputStream
();
EWKBTarget
target
=
new
EWKBTarget
(
output
,
dimension
Target
.
getDimensionSystem
()
);
EWKBTarget
target
=
new
EWKBTarget
(
output
,
dimension
System
);
parseEWKT
(
ewkt
,
target
);
return
output
.
toByteArray
();
}
...
...
h2/src/main/org/h2/util/geometry/GeometryUtils.java
浏览文件 @
000f7bb6
...
...
@@ -468,7 +468,7 @@ public final class GeometryUtils {
*/
public
static
double
[]
getEnvelope
(
byte
[]
ewkb
)
{
EnvelopeAndDimensionSystemTarget
target
=
new
EnvelopeAndDimensionSystemTarget
();
EWKBUtils
.
parseE
KW
B
(
ewkb
,
target
);
EWKBUtils
.
parseE
WK
B
(
ewkb
,
target
);
return
target
.
getEnvelope
();
}
...
...
h2/src/main/org/h2/util/geometry/JTSUtils.java
浏览文件 @
000f7bb6
...
...
@@ -198,10 +198,23 @@ public final class JTSUtils {
public
static
Geometry
ewkb2geometry
(
byte
[]
ewkb
)
{
// Determine dimension system first
DimensionSystemTarget
dimensionTarget
=
new
DimensionSystemTarget
();
EWKBUtils
.
parseE
KW
B
(
ewkb
,
dimensionTarget
);
EWKBUtils
.
parseE
WK
B
(
ewkb
,
dimensionTarget
);
// Generate a Geometry
GeometryTarget
target
=
new
GeometryTarget
(
dimensionTarget
.
getDimensionSystem
());
EWKBUtils
.
parseEKWB
(
ewkb
,
target
);
return
ewkb2geometry
(
ewkb
,
dimensionTarget
.
getDimensionSystem
());
}
/**
* Converts EWKB to a JTS geometry object.
*
* @param ewkb
* source EWKB
* @param dimensionSystem
* dimension system
* @return JTS geometry object
*/
public
static
Geometry
ewkb2geometry
(
byte
[]
ewkb
,
int
dimensionSystem
)
{
GeometryTarget
target
=
new
GeometryTarget
(
dimensionSystem
);
EWKBUtils
.
parseEWKB
(
ewkb
,
target
);
return
target
.
getGeometry
();
}
...
...
@@ -216,9 +229,23 @@ public final class JTSUtils {
// Determine dimension system first
DimensionSystemTarget
dimensionTarget
=
new
DimensionSystemTarget
();
parseGeometry
(
geometry
,
dimensionTarget
);
// Write an EWKB
return
geometry2ewkb
(
geometry
,
dimensionTarget
.
getDimensionSystem
());
}
/**
* Converts Geometry to EWKB.
*
* @param geometry
* source geometry
* @param dimensionSystem
* dimension system
* @return EWKB representation
*/
public
static
byte
[]
geometry2ewkb
(
Geometry
geometry
,
int
dimensionSystem
)
{
// Write an EWKB
ByteArrayOutputStream
output
=
new
ByteArrayOutputStream
();
EWKBTarget
target
=
new
EWKBTarget
(
output
,
dimension
Target
.
getDimensionSystem
()
);
EWKBTarget
target
=
new
EWKBTarget
(
output
,
dimension
System
);
parseGeometry
(
geometry
,
target
);
return
output
.
toByteArray
();
}
...
...
@@ -231,7 +258,7 @@ public final class JTSUtils {
* @param target
* output target
*/
p
rivate
static
void
parseGeometry
(
Geometry
geometry
,
Target
target
)
{
p
ublic
static
void
parseGeometry
(
Geometry
geometry
,
Target
target
)
{
parseGeometry
(
geometry
,
target
,
0
,
0
);
}
...
...
h2/src/main/org/h2/value/Value.java
浏览文件 @
000f7bb6
...
...
@@ -1215,7 +1215,7 @@ public abstract class Value {
private
ValueGeometry
convertToGeometry
()
{
switch
(
getType
())
{
case
BYTES:
return
ValueGeometry
.
get
(
getBytesNoCopy
());
return
ValueGeometry
.
get
FromEWKB
(
getBytesNoCopy
());
case
JAVA_OBJECT:
Object
object
=
JdbcUtils
.
deserialize
(
getBytesNoCopy
(),
getDataHandler
());
if
(
DataType
.
isGeometry
(
object
))
{
...
...
h2/src/main/org/h2/value/ValueGeometry.java
浏览文件 @
000f7bb6
...
...
@@ -13,8 +13,10 @@ import org.h2.message.DbException;
import
org.h2.util.Bits
;
import
org.h2.util.StringUtils
;
import
org.h2.util.Utils
;
import
org.h2.util.geometry.EWKBUtils
;
import
org.h2.util.geometry.EWKTUtils
;
import
org.h2.util.geometry.GeometryUtils
;
import
org.h2.util.geometry.GeometryUtils.EnvelopeAndDimensionSystemTarget
;
import
org.h2.util.geometry.JTSUtils
;
import
org.locationtech.jts.geom.Geometry
;
...
...
@@ -40,10 +42,9 @@ public class ValueGeometry extends Value {
private
final
int
hashCode
;
/**
* The value. Converted from WKB only on request as conversion from/to WKB
* cost a significant amount of CPU cycles.
* Dimension system. -1 if not known yet.
*/
private
Object
geometry
;
private
int
dimensionSystem
;
/**
* The envelope of the value. Calculated only on request.
...
...
@@ -51,13 +52,23 @@ public class ValueGeometry extends Value {
private
double
[]
envelope
;
/**
* Create a new geometry objects.
* The value. Converted from WKB only on request as conversion from/to WKB
* cost a significant amount of CPU cycles.
*/
private
Object
geometry
;
/**
* Create a new geometry object.
*
* @param bytes the EWKB bytes
* @param dimensionSystem dimension system
* @param envelope the envelope
*/
private
ValueGeometry
(
byte
[]
bytes
)
{
private
ValueGeometry
(
byte
[]
bytes
,
int
dimensionSystem
,
double
[]
envelope
)
{
this
.
bytes
=
bytes
;
this
.
hashCode
=
Arrays
.
hashCode
(
bytes
);
this
.
dimensionSystem
=
dimensionSystem
;
this
.
envelope
=
envelope
;
}
/**
...
...
@@ -68,7 +79,16 @@ public class ValueGeometry extends Value {
* @return the value
*/
public
static
ValueGeometry
getFromGeometry
(
Object
o
)
{
return
get
(
JTSUtils
.
geometry2ewkb
((
Geometry
)
o
));
try
{
EnvelopeAndDimensionSystemTarget
target
=
new
EnvelopeAndDimensionSystemTarget
();
Geometry
g
=
(
Geometry
)
o
;
JTSUtils
.
parseGeometry
(
g
,
target
);
int
dimensionSystem
=
target
.
getDimensionSystem
();
return
(
ValueGeometry
)
Value
.
cache
(
new
ValueGeometry
(
JTSUtils
.
geometry2ewkb
(
g
,
dimensionSystem
),
dimensionSystem
,
target
.
getEnvelope
()));
}
catch
(
RuntimeException
ex
)
{
throw
DbException
.
convert
(
ex
);
}
}
/**
...
...
@@ -79,7 +99,11 @@ public class ValueGeometry extends Value {
*/
public
static
ValueGeometry
get
(
String
s
)
{
try
{
return
get
(
EWKTUtils
.
ewkt2ewkb
(
s
));
EnvelopeAndDimensionSystemTarget
target
=
new
EnvelopeAndDimensionSystemTarget
();
EWKTUtils
.
parseEWKT
(
s
,
target
);
int
dimensionSystem
=
target
.
getDimensionSystem
();
return
(
ValueGeometry
)
Value
.
cache
(
new
ValueGeometry
(
EWKTUtils
.
ewkt2ewkb
(
s
,
dimensionSystem
),
dimensionSystem
,
target
.
getEnvelope
()));
}
catch
(
RuntimeException
ex
)
{
throw
DbException
.
convert
(
ex
);
}
...
...
@@ -98,13 +122,42 @@ public class ValueGeometry extends Value {
}
/**
* Get or create a geometry value for the given
geometry
.
* Get or create a geometry value for the given
internal EWKB representation
.
*
* @param bytes the WKB representation of the geometry
* @param bytes the WKB representation of the geometry
. May not be modified.
* @return the value
*/
public
static
ValueGeometry
get
(
byte
[]
bytes
)
{
return
(
ValueGeometry
)
Value
.
cache
(
new
ValueGeometry
(
bytes
));
return
(
ValueGeometry
)
Value
.
cache
(
new
ValueGeometry
(
bytes
,
-
1
,
null
));
}
/**
* Get or create a geometry value for the given EWKB value.
*
* @param bytes the WKB representation of the geometry
* @return the value
*/
public
static
ValueGeometry
getFromEWKB
(
byte
[]
bytes
)
{
try
{
EnvelopeAndDimensionSystemTarget
target
=
new
EnvelopeAndDimensionSystemTarget
();
EWKBUtils
.
parseEWKB
(
bytes
,
target
);
int
dimensionSystem
=
target
.
getDimensionSystem
();
return
(
ValueGeometry
)
Value
.
cache
(
new
ValueGeometry
(
EWKBUtils
.
ewkb2ewkb
(
bytes
,
dimensionSystem
),
dimensionSystem
,
target
.
getEnvelope
()));
}
catch
(
RuntimeException
ex
)
{
throw
DbException
.
convert
(
ex
);
}
}
/**
* Creates a geometry value for the given envelope.
*
* @param envelope envelope. May not be modified.
* @return the value
*/
public
static
ValueGeometry
fromEnvelope
(
double
[]
envelope
)
{
return
(
ValueGeometry
)
Value
.
cache
(
new
ValueGeometry
(
GeometryUtils
.
envelope2wkb
(
envelope
),
GeometryUtils
.
DIMENSION_SYSTEM_XY
,
envelope
));
}
/**
...
...
@@ -116,7 +169,7 @@ public class ValueGeometry extends Value {
public
Object
getGeometry
()
{
if
(
geometry
==
null
)
{
try
{
geometry
=
JTSUtils
.
ewkb2geometry
(
bytes
);
geometry
=
JTSUtils
.
ewkb2geometry
(
bytes
,
getDimensionSystem
()
);
}
catch
(
RuntimeException
ex
)
{
throw
DbException
.
convert
(
ex
);
}
...
...
@@ -153,15 +206,32 @@ public class ValueGeometry extends Value {
return
0
;
}
private
void
calculateInfo
()
{
if
(
dimensionSystem
<
0
)
{
EnvelopeAndDimensionSystemTarget
target
=
new
EnvelopeAndDimensionSystemTarget
();
EWKBUtils
.
parseEWKB
(
bytes
,
target
);
envelope
=
target
.
getEnvelope
();
dimensionSystem
=
target
.
getDimensionSystem
();
}
}
/**
* Return a minimal dimension system that can be used for this geometry.
*
* @return dimension system
*/
public
int
getDimensionSystem
()
{
calculateInfo
();
return
dimensionSystem
;
}
/**
* Return an envelope of this geometry. Do not modify the returned value.
*
* @return envelope of this geometry
*/
public
double
[]
getEnvelopeNoCopy
()
{
if
(
envelope
==
null
)
{
envelope
=
GeometryUtils
.
getEnvelope
(
bytes
);
}
calculateInfo
();
return
envelope
;
}
...
...
@@ -183,7 +253,7 @@ public class ValueGeometry extends Value {
* @return the union of this geometry envelope and another geometry envelope
*/
public
Value
getEnvelopeUnion
(
ValueGeometry
r
)
{
return
get
(
GeometryUtils
.
envelope2wkb
(
GeometryUtils
.
union
(
getEnvelopeNoCopy
(),
r
.
getEnvelopeNoCopy
()
)));
return
fromEnvelope
(
GeometryUtils
.
union
(
getEnvelopeNoCopy
(),
r
.
getEnvelopeNoCopy
(
)));
}
@Override
...
...
@@ -247,12 +317,12 @@ public class ValueGeometry extends Value {
@Override
public
int
getMemory
()
{
return
getEWKB
()
.
length
*
20
+
24
;
return
bytes
.
length
*
20
+
24
;
}
@Override
public
boolean
equals
(
Object
other
)
{
return
other
instanceof
ValueGeometry
&&
Arrays
.
equals
(
getEWKB
(),
((
ValueGeometry
)
other
).
getEWKB
()
);
return
other
instanceof
ValueGeometry
&&
Arrays
.
equals
(
bytes
,
((
ValueGeometry
)
other
).
bytes
);
}
/**
...
...
@@ -261,7 +331,7 @@ public class ValueGeometry extends Value {
* @return the extended well-known text
*/
public
String
getEWKT
()
{
return
EWKTUtils
.
ewkb2ewkt
(
bytes
);
return
EWKTUtils
.
ewkb2ewkt
(
bytes
,
getDimensionSystem
()
);
}
/**
...
...
h2/src/test/org/h2/test/unit/TestGeometryUtils.java
浏览文件 @
000f7bb6
...
...
@@ -156,7 +156,7 @@ public class TestGeometryUtils extends TestBase {
Envelope
envelopeFromJTS
=
geometryFromJTS
.
getEnvelopeInternal
();
testEnvelope
(
envelopeFromJTS
,
GeometryUtils
.
getEnvelope
(
wkbFromJTS
));
EnvelopeAndDimensionSystemTarget
target
=
new
EnvelopeAndDimensionSystemTarget
();
EWKBUtils
.
parseE
KW
B
(
wkbFromJTS
,
target
);
EWKBUtils
.
parseE
WK
B
(
wkbFromJTS
,
target
);
testEnvelope
(
envelopeFromJTS
,
target
.
getEnvelope
());
// Test dimensions
...
...
@@ -242,10 +242,10 @@ public class TestGeometryUtils extends TestBase {
private
void
testDimensions
(
int
expected
,
byte
[]
ewkb
)
{
DimensionSystemTarget
dst
=
new
DimensionSystemTarget
();
EWKBUtils
.
parseE
KW
B
(
ewkb
,
dst
);
EWKBUtils
.
parseE
WK
B
(
ewkb
,
dst
);
assertEquals
(
expected
,
dst
.
getDimensionSystem
());
EnvelopeAndDimensionSystemTarget
envelopeAndDimensionTarget
=
new
EnvelopeAndDimensionSystemTarget
();
EWKBUtils
.
parseE
KW
B
(
ewkb
,
envelopeAndDimensionTarget
);
EWKBUtils
.
parseE
WK
B
(
ewkb
,
envelopeAndDimensionTarget
);
assertEquals
(
expected
,
envelopeAndDimensionTarget
.
getDimensionSystem
());
}
...
...
h2/src/tools/org/h2/build/doc/dictionary.txt
浏览文件 @
000f7bb6
...
...
@@ -793,4 +793,4 @@ immediate hhmmss scheduled hhmm prematurely postponed arranges subexpression sub
minxf maxxf minyf maxyf bminxf bmaxxf bminyf bmaxyf
minxd maxxd minyd maxyd bminxd bmaxxd bminyd bmaxyd
interior envelopes multilinestring multipoint packed exterior normalization awkward determination subgeometries
xym
ekwb
normalizes coord setz xyzm geometrycollection multipolygon mixup rings polygons
xym normalizes coord setz xyzm geometrycollection multipolygon mixup rings polygons
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论