Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support to MultiPartM #6

Closed
wants to merge 8 commits into from
130 changes: 130 additions & 0 deletions src/main/scala/com/esri/gdb/FieldMultiPartM.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package com.esri.gdb

import org.apache.spark.sql.Row
import org.apache.spark.sql.types._

import java.nio.ByteBuffer

class FieldMultiPartM(val field: StructField, xOrig: Double, yOrig: Double, xyScale: Double, mOrig: Double, mScale: Double) extends FieldBytes {

override type T = Row

override def readNull(): T = null.asInstanceOf[Row]

override def readValue(byteBuffer: ByteBuffer, oid: Int): Row = {
val blob = getByteBuffer(byteBuffer)
val geomType = blob.getVarUInt
val hasCurveDesc = (geomType & 0x20000000L) != 0L
val numPoints = blob.getVarUInt.toInt
// println(f"geomType=$geomType%X numPoints=$numPoints")
if (numPoints > 0) {
val coords = new Array[Double](numPoints * 3)
val numParts = blob.getVarUInt.toInt
val curveDesc = if (hasCurveDesc) blob.getVarUInt else 0
val xmin = blob.getVarUInt / xyScale + xOrig
val ymin = blob.getVarUInt / xyScale + yOrig
val xmax = blob.getVarUInt / xyScale + xmin
val ymax = blob.getVarUInt / xyScale + ymin

var dx = 0L
var dy = 0L
var dm = 0L
var ix = 0
var iy = 1
var im = 2

if (numParts > 1) {
// TODO - Check on this !
val parts = new Array[Int](numParts)
var p = 0
var n = 1
var sum = 0
while (n < numParts) { // Read numParts-1
val numXY = blob.getVarUInt.toInt
parts(p) = numXY
sum += numXY
n += 1
p += 1
}
parts(p) = numPoints - sum
p = 0
while (p < numParts) {
val numPointsInPart = parts(p)
n = 0
while (n < numPointsInPart) {
dx += blob.getVarInt
dy += blob.getVarInt
coords(ix) = dx / xyScale + xOrig
coords(iy) = dy / xyScale + yOrig
ix += 3
iy += 3
n += 1
}
p += 1
}
n = 0
while (n < numPoints) {
val varInt = try blob.getVarInt catch {case e: Throwable => -2}
if (varInt < 0L) {
coords(im) = Double.NaN
} else {
dm += varInt
coords(im) = dm / mScale + mOrig
}
im += 3
n += 1
}
Row(xmin, ymin, xmax, ymax, parts, coords)
}
else {
var n = 0
while (n < numPoints) {
dx += blob.getVarInt
dy += blob.getVarInt
coords(ix) = dx / xyScale + xOrig
coords(iy) = dy / xyScale + yOrig
ix += 3
iy += 3
n += 1
}
n = 0
while (n < numPoints) {
val varInt = try blob.getVarInt catch {case e: Throwable => -2}
if (varInt < 0L) {
coords(im) = Double.NaN
} else {
dm += varInt
coords(im) = dm / mScale + mOrig
}
im += 3
n += 1
}
Row(xmin, ymin, xmax, ymax, Array(numPoints), coords)
}
} else {
Row(0.0, 0.0, 0.0, 0.0, Array.empty[Int], Array.empty[Double])
}
}
}

object FieldMultiPartM extends Serializable {
def apply(name: String,
nullable: Boolean,
metadata: Metadata,
xOrig: Double,
yOrig: Double,
xyScale: Double,
mOrig: Double,
mScale: Double
): FieldMultiPartM = {
new FieldMultiPartM(StructField(name,
StructType(Seq(
StructField("xmin", DoubleType, nullable),
StructField("ymin", DoubleType, nullable),
StructField("xmax", DoubleType, nullable),
StructField("ymax", DoubleType, nullable),
StructField("parts", ArrayType(IntegerType), nullable),
StructField("coords", ArrayType(DoubleType), nullable))
), nullable, metadata), xOrig, yOrig, xyScale, mOrig, mScale)
}
}
2 changes: 1 addition & 1 deletion src/main/scala/com/esri/gdb/FieldMultiPartZ.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class FieldMultiPartZ(val field: StructField, xOrig: Double, yOrig: Double, xySc
val numPoints = blob.getVarUInt.toInt
// println(f"geomType=$geomType%X numPoints=$numPoints")
if (numPoints > 0) {
val coords = new Array[Double](numPoints * 4)
val coords = new Array[Double](numPoints * 3)
val numParts = blob.getVarUInt.toInt
val curveDesc = if (hasCurveDesc) blob.getVarUInt else 0
val xmin = blob.getVarUInt / xyScale + xOrig
Expand Down
36 changes: 28 additions & 8 deletions src/main/scala/com/esri/gdb/FieldMultiPartZM.scala
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,13 @@ class FieldMultiPartZM(val field: StructField,

n = 0
while (n < numPoints) {
dz += blob.getVarInt
coords(iz) = dz / zScale + zOrig
val varInt = try blob.getVarInt catch {case e: Throwable => -2}
if (varInt < 0L) {
coords(im) = Double.NaN
} else {
dz += varInt
coords(iz) = dz / zScale + zOrig
}
iz += 4
n += 1
}
Expand All @@ -96,8 +101,13 @@ class FieldMultiPartZM(val field: StructField,
blob.reset() // goes to mark position.
}
while (n < numPoints) {
dm += blob.getVarInt
coords(im) = dm / mScale + mOrig
val varInt = try blob.getVarInt catch {case e: Throwable => -2}
if (varInt < 0L) {
coords(im) = Double.NaN
} else {
dm += varInt
coords(im) = dm / mScale + mOrig
}
im += 4
n += 1
}
Expand All @@ -118,8 +128,13 @@ class FieldMultiPartZM(val field: StructField,
}
n = 0
while (n < numPoints) {
dz += blob.getVarInt
coords(iz) = dz / zScale + zOrig
val varInt = try blob.getVarInt catch {case e: Throwable => -2}
if (varInt < 0L) {
coords(im) = Double.NaN
} else {
dz += varInt
coords(iz) = dz / zScale + zOrig
}
iz += 4
n += 1
}
Expand All @@ -137,8 +152,13 @@ class FieldMultiPartZM(val field: StructField,
blob.reset() // Go to marked position.
}
while (n < numPoints) {
dm += blob.getVarInt
coords(im) = dm / mScale + mOrig
val varInt = try blob.getVarInt catch {case e: Throwable => -2}
if (varInt < 0L) {
coords(im) = Double.NaN
} else {
dm += varInt
coords(im) = dm / mScale + mOrig
}
im += 4
n += 1
}
Expand Down
2 changes: 2 additions & 0 deletions src/main/scala/com/esri/gdb/GDBTable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -399,13 +399,15 @@ object GDBTable extends Serializable {
case 3 => // Polyline
geometryProp match {
case 0x00 => FieldMultiPart(name, nullable, metadata, xOrig, yOrig, xyScale)
case 0x40 => FieldMultiPartM(name, nullable, metadata, xOrig, yOrig, xyScale, mOrig, mScale)
case 0x80 => FieldMultiPartZ(name, nullable, metadata, xOrig, yOrig, xyScale, zOrig, zScale)
case 0xC0 => FieldMultiPartZM(name, nullable, metadata, xOrig, yOrig, xyScale, zOrig, zScale, mOrig, mScale)
case _ => throw new RuntimeException(f"Cannot parse (yet) polyline with geometryProp value of $geometryProp%X :-(")
}
case 4 | 5 => // Polygon
geometryProp match {
case 0x00 => FieldMultiPart(name, nullable, metadata, xOrig, yOrig, xyScale)
case 0x40 => FieldMultiPartM(name, nullable, metadata, xOrig, yOrig, xyScale, mOrig, mScale)
case 0x80 => FieldMultiPartZ(name, nullable, metadata, xOrig, yOrig, xyScale, zOrig, zScale)
case 0xC0 => FieldMultiPartZM(name, nullable, metadata, xOrig, yOrig, xyScale, zOrig, zScale, mOrig, mScale)
case _ => throw new RuntimeException(f"Cannot parse (yet) polygons with geometryProp value of $geometryProp%X :-(")
Expand Down