text: import LineString from './LineString'
  import CoordinateList from './CoordinateList'
  import Geometry from './Geometry'
  import hasInterface from '../../../../hasInterface'
  import Coordinate from './Coordinate'
  import Point from './Point'
  import Double from '../../../../java/lang/Double'
  import GeometryComponentFilter from './GeometryComponentFilter'
  import CoordinateSequence from './CoordinateSequence'
  import Envelope from './Envelope'
  
  export default class OctagonalEnvelope {
    constructor () {
      this._minX = Double.NaN
      this._maxX = null
      this._minY = null
      this._maxY = null
      this._minA = null
      this._maxA = null
      this._minB = null
      this._maxB = null
      if (arguments.length === 0) {} else if (arguments.length === 1) {
        if (arguments[0] instanceof Coordinate) {
          const p = arguments[0]
          this.expandToInclude(p)
        } else if (arguments[0] instanceof Envelope) {
          const env = arguments[0]
          this.expandToInclude(env)
        } else if (arguments[0] instanceof OctagonalEnvelope) {
          const oct = arguments[0]
          this.expandToInclude(oct)
        } else if (arguments[0] instanceof Geometry) {
          const geom = arguments[0]
          this.expandToInclude(geom)
        }
      } else if (arguments.length === 2) {
        const p0 = arguments[0]
        const p1 = arguments[1]
        this.expandToInclude(p0)
        this.expandToInclude(p1)
      }
    }
    toGeometry (geomFactory) {
      if (this.isNull()) {
        return geomFactory.createPoint(null)
      }
      const px00 = new Coordinate(this._minX, this._minA - this._minX)
      const px01 = new Coordinate(this._minX, this._minX - this._minB)
      const px10 = new Coordinate(this._maxX, this._maxX - this._maxB)
      const px11 = new Coordinate(this._maxX, this._maxA - this._maxX)
      const py00 = new Coordinate(this._minA - this._minY, this._minY)
      const py01 = new Coordinate(this._minY + this._maxB, this._minY)
      const py10 = new Coordinate(this._maxY + this._minB, this._maxY)
      const py11 = new Coordinate(this._maxA - this._maxY, this._maxY)
      const pm = geomFactory.getPrecisionModel()
      pm.makePrecise(px00)
      pm.makePrecise(px01)
      pm.makePrecise(px10)
      pm.makePrecise(px11)
      pm.makePrecise(py00)
      pm.makePrecise(py01)
      pm.makePrecise(py10)
      pm.makePrecise(py11)
      const coordList = new CoordinateList()
      coordList.add(px00, false)
      coordList.add(px01, false)
      coordList.add(py10, false)
      coordList.add(py11, false)
      coordList.add(px11, false)
      coordList.add(px10, false)
      coordList.add(py01, false)
      coordList.add(py00, false)
      if (coordList.size() === 1) {
        return geomFactory.createPoint(px00)
      }
      if (coordList.size() === 2) {
        const pts = coordList.toCoordinateArray()
        return geomFactory.createLineString(pts)
      }
      coordList.add(px00, false)
      const pts = coordList.toCoordinateArray()
      return geomFactory.createPolygon(geomFactory.createLinearRing(pts), null)
    }
    getMinA () {
      return this._minA
    }
    getMaxB () {
      return this._maxB
    }
    isValid () {
      if (this.isNull()) return true
      return this._minX <= this._maxX && this._minY <= this._maxY && this._minA <= this._maxA && this._minB <= this._maxB
    }
    isNull () {
      return Double.isNaN(this._minX)
    }
    getMaxX () {
      return this._maxX
    }
    intersects () {
      if (arguments[0] instanceof OctagonalEnvelope) {
        const other = arguments[0]
        if (this.isNull() || other.isNull()) {
          return false
        }
        if (this._minX > other._maxX) return false
        if (this._maxX < other._minX) return false
        if (this._minY > other._maxY) return false
        if (this._maxY < other._minY) return false
        if (this._minA > other._maxA) return false
        if (this._maxA < other._minA) return false
        if (this._minB > other._maxB) return false
        if (this._maxB < other._minB) return false
        return true
      } else if (arguments[0] instanceof Coordinate) {
        const p = arguments[0]
        if (this._minX > p.x) return false
        if (this._maxX < p.x) return false
        if (this._minY > p.y) return false
        if (this._maxY < p.y) return false
        const A = OctagonalEnvelope.computeA(p.x, p.y)
        const B = OctagonalEnvelope.computeB(p.x, p.y)
        if (this._minA > A) return false
        if (this._maxA < A) return false
        if (this._minB > B) return false
        if (this._maxB < B) return false
        return true
      }
    }
    getMinY () {
      return this._minY
    }
    getMinX () {
      return this._minX
    }
    expandToInclude () {
      if (arguments.length === 1) {
        if (arguments[0] instanceof Geometry) {
          const g = arguments[0]
          g.apply(new BoundingOctagonComponentFilter(this))
        } else if (hasInterface(arguments[0], CoordinateSequence)) {
          const seq = arguments[0]
          for (let i = 0; i < seq.size(); i++) {
            const x = seq.getX(i)
            const y = seq.getY(i)
            this.expandToInclude(x, y)
          }
          return this
        } else if (arguments[0] instanceof OctagonalEnvelope) {
          const oct = arguments[0]
          if (oct.isNull()) return this
          if (this.isNull()) {
            this._minX = oct._minX
            this._maxX = oct._maxX
            this._minY = oct._minY
            this._maxY = oct._maxY
            this._minA = oct._minA
            this._maxA = oct._maxA
            this._minB = oct._minB
            this._maxB = oct._maxB
            return this
          }
          if (oct._minX < this._minX) this._minX = oct._minX
          if (oct._maxX > this._maxX) this._maxX = oct._maxX
          if (oct._minY < this._minY) this._minY = oct._minY
          if (oct._maxY > this._maxY) this._maxY = oct._maxY
          if (oct._minA < this._minA) this._minA = oct._minA
          if (oct._maxA > this._maxA) this._maxA = oct._maxA
          if (oct._minB < this._minB) this._minB = oct._minB
          if (oct._maxB > this._maxB) this._maxB = oct._maxB
          return this
        } else if (arguments[0] instanceof Coordinate) {
          const p = arguments[0]
          this.expandToInclude(p.x, p.y)
          return this
        } else if (arguments[0] instanceof Envelope) {
          const env = arguments[0]
          this.expandToInclude(env.getMinX(), env.getMinY())
          this.expandToInclude(env.getMinX(), env.getMaxY())
          this.expandToInclude(env.getMaxX(), env.getMinY())
          this.expandToInclude(env.getMaxX(), env.getMaxY())
          return this
        }
      } else if (arguments.length === 2) {
        const x = arguments[0]
        const y = arguments[1]
        const A = OctagonalEnvelope.computeA(x, y)
        const B = OctagonalEnvelope.computeB(x, y)
        if (this.isNull()) {
          this._minX = x
          this._maxX = x
          this._minY = y
          this._maxY = y
          this._minA = A
          this._maxA = A
          this._minB = B
          this._maxB = B
        } else {
          if (x < this._minX) this._minX = x
          if (x > this._maxX) this._maxX = x
          if (y < this._minY) this._minY = y
          if (y > this._maxY) this._maxY = y
          if (A < this._minA) this._minA = A
          if (A > this._maxA) this._maxA = A
          if (B < this._minB) this._minB = B
          if (B > this._maxB) this._maxB = B
        }
        return this
      }
    }
    getMinB () {
      return this._minB
    }
    setToNull () {
      this._minX = Double.NaN
    }
    expandBy (distance) {
      if (this.isNull()) return null
      const diagonalDistance = OctagonalEnvelope.SQRT2 * distance
      this._minX -= distance
      this._maxX += distance
      this._minY -= distance
      this._maxY += distance
      this._minA -= diagonalDistance
      this._maxA += diagonalDistance
      this._minB -= diagonalDistance
      this._maxB += diagonalDistance
      if (!this.isValid()) this.setToNull()
    }
    getMaxA () {
      return this._maxA
    }
    contains (other) {
      if (this.isNull() || other.isNull()) {
        return false
      }
      return other._minX >= this._minX && other._maxX <= this._maxX && other._minY >= this._minY && other._maxY <= this._maxY && other._minA >= this._minA && other._maxA <= this._maxA && other._minB >= this._minB && other._maxB <= this._maxB
    }
    getMaxY () {
      return this._maxY
    }
    interfaces_ () {
      return []
    }
    getClass () {
      return OctagonalEnvelope
    }
    static octagonalEnvelope (geom) {
      return new OctagonalEnvelope(geom).toGeometry(geom.getFactory())
    }
    static computeB (x, y) {
      return x - y
    }
    static computeA (x, y) {
      return x + y
    }
    static get BoundingOctagonComponentFilter () { return BoundingOctagonComponentFilter }
    static get SQRT2 () { return Math.sqrt(2.0) }
  }
  
  class BoundingOctagonComponentFilter {
    constructor (oe) {
      this.oe = oe || null
    }
    filter (geom) {
      if (geom instanceof LineString) {
        this.oe.expandToInclude(geom.getCoordinateSequence())
      } else if (geom instanceof Point) {
        this.oe.expandToInclude(geom.getCoordinateSequence())
      }
    }
    interfaces_ () {
      return [GeometryComponentFilter]
    }
    getClass () {
      return BoundingOctagonComponentFilter
    }
  }
  