All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.ucr.cs.bdlab.beast.sql.ST_FromSpatialParquet.scala Maven / Gradle / Ivy

/*
 * Copyright 2020 University of California, Riverside
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package edu.ucr.cs.bdlab.beast.sql

import org.apache.spark.beast.sql.GeometryDataType
import org.apache.spark.sql.catalyst.InternalRow
import org.apache.spark.sql.catalyst.analysis.TypeCheckResult
import org.apache.spark.sql.catalyst.expressions.Expression
import org.apache.spark.sql.catalyst.expressions.codegen.CodegenFallback
import org.apache.spark.sql.catalyst.util.ArrayData
import org.apache.spark.sql.types._
import org.locationtech.jts.geom._

/**
 * Converts a geometry encoded using the SpatialParquet format back into a geometry.
 * @param inputExpressions
 * @see [[ST_ToSpatialParquet]]
 */
case class ST_FromSpatialParquet(inputExpressions: Seq[Expression]) extends Expression with CodegenFallback {

  protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]): Expression = copy(newChildren)

  override def checkInputDataTypes(): TypeCheckResult = {
    if (inputExpressions.length == 1 && inputExpressions.forall(_.dataType == SpatialParquetHelper.SpatialParquetGeometryType))
      TypeCheckResult.TypeCheckSuccess
    else
      TypeCheckResult.TypeCheckFailure(s"Function $prettyName expects one encoded-geometry input")
  }

  override def children: Seq[Expression] = inputExpressions

  override def nullable: Boolean = false

  override def foldable: Boolean = inputExpressions.forall(_.foldable)

  override def dataType: DataType = GeometryDataType

  override def eval(input: InternalRow): Any = {
    val encodedGeometry: InternalRow = inputExpressions.map(e => e.eval(input)).head.asInstanceOf[InternalRow]
    val srid = encodedGeometry.getInt(0)
    val factory = new GeometryFactory(new PrecisionModel(PrecisionModel.FLOATING), srid)
    val encodedSubGeometries: ArrayData = encodedGeometry.getArray(1)
    val subgeometries = new Array[Geometry](encodedSubGeometries.numElements)
    for (i <- 0 until encodedSubGeometries.numElements)
      subgeometries(i) = SpatialParquetHelper.decodeGeometry(encodedSubGeometries.getStruct(i, 5), factory)

    val geometry =  if (subgeometries.length == 1)
      subgeometries.head
    else if (subgeometries.forall(_.isInstanceOf[Point]))
      factory.createMultiPoint(subgeometries.map(_.asInstanceOf[Point]))
    else if (subgeometries.forall(_.isInstanceOf[LineString]))
      factory.createMultiLineString(subgeometries.map(_.asInstanceOf[LineString]))
    else if (subgeometries.forall(_.isInstanceOf[Polygon]))
      factory.createMultiPolygon(subgeometries.map(_.asInstanceOf[Polygon]))
    else
      factory.createGeometryCollection(subgeometries)
    GeometryDataType.setGeometryInRow(geometry)
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy