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

org.tinfour.svm.SvmFlatFixer Maven / Gradle / Ivy

Go to download

The Simple Volumetric Model (SVM) uses bathymetry to estimate the capacity of lakes and reservoirs

There is a newer version: 2.1.7
Show newest version
/* --------------------------------------------------------------------
 * Copyright (C) 2019  Gary W. Lucas.
 *
 * 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.
 * ---------------------------------------------------------------------
 */

 /*
 * -----------------------------------------------------------------------
 *
 * Revision History:
 * Date     Name         Description
 * ------   ---------    -------------------------------------------------
 * 04/2019  G. Lucas     Created  
 *
 * Notes:
 *   At this time, the flat-fixer is not completely working.
 *   Part of its action is to subdivide triangles creating a new
 *   subset of non-flat triangles. Unfortunately, near the constraint
 *   boundaries, it can produce a potentially unlimited number of  
 *   "skinny" triangles.  I am investigating this problem.
 * -----------------------------------------------------------------------
 */
package org.tinfour.svm;

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
import org.tinfour.common.GeometricOperations;
import org.tinfour.common.IIncrementalTin;
import org.tinfour.common.IQuadEdge;
import org.tinfour.common.Thresholds;
import org.tinfour.common.Vertex;

/**
 * Implements logic for remediating flat triangles.
 */
class SvmFlatFixer {

  private final IIncrementalTin tin;
  private final double zShore;

  private int nRemediations;
  private double remediatedArea;
  private double remediatedVolume;

  private boolean isEquiv(double a, double b) {
    return Math.abs(a - b) < 1.0e-6;
  }

  SvmFlatFixer(IIncrementalTin tin, double zShore) {
    this.tin = tin;
    this.zShore = zShore;
  }

  List fixFlats(PrintStream ps) {
    // Initialize the visited bit-set with the perimeter.
    // Doing so will prevent the perimeter from being included
    // in the computations of means as well as in the searches to follow
    Thresholds thresholds = tin.getThresholds();
    GeometricOperations geoOp = new GeometricOperations(thresholds);

    List fixList = new ArrayList<>();
    int iMax = tin.getMaximumEdgeAllocationIndex();
    BitSet visited = new BitSet(iMax);
    // we don't want to insert any points on the perimeter
    // so mark the perimeter as visited.
    List perimeter = tin.getPerimeter();
    for (IQuadEdge edge : perimeter) {
      int index = edge.getIndex();
      visited.set(index);
      visited.set(index ^ 1); // XOR to get the dual
    }

    for (IQuadEdge edge : tin.edges()) {
      int index = edge.getIndex();
      if (visited.get(index)) {
        continue;
      }
      visited.set(index);
      visited.set(index ^ 1); // XOR to get the dual
      if (edge.isConstrained()) {
        continue;
      }
      Vertex A = edge.getA();
      Vertex B = edge.getB();
      if (isEquiv(A.getZ(), zShore) && isEquiv(B.getZ(), zShore)) {
        IQuadEdge dual = edge.getDual();
        Vertex C = edge.getForward().getB();
        Vertex D = dual.getForward().getB();
        if (C == null || D == null) {
          continue;  // not anticipated to happen
        }
        if (isEquiv(C.getZ(), zShore)) {
          if (!isEquiv(D.getZ(), zShore)) {
            fixList.add(edge);
          }
        } else if (isEquiv(D.getZ(), zShore)) {
          // we've already established that C.getZ() != zShore
          fixList.add(dual);
        }
      }
    }

    List fixVertices = new ArrayList<>(fixList.size());
    for (IQuadEdge edge : fixList) {
      Vertex A = edge.getA();
      Vertex B = edge.getB();
      Vertex C = edge.getForward().getB();
      Vertex D = edge.getForwardFromDual().getB();

      double area = geoOp.area(A, B, C);
      if (area < 1) {
        continue;
      }

      double mX = (A.getX() + B.getX()) / 2;
      double mY = (A.getY() + B.getY()) / 2;
      nRemediations++;
      double sC = C.getDistance(mX, mY);
      double sD = D.getDistance(mX, mY);
      double mZ;
      if (D.getAuxiliaryIndex() == 1) {
        // since the earlier vertex was already interpolated
        // the model just propagates its value inward.
        mZ = D.getZ();
      } else {
        // interpolate a new dept value combining an actual
        // sample (D) and a shoreline vertex (C)
        mZ = (sC * D.getZ() + sD * C.getZ()) / (sC + sD);
        if (zShore - mZ < 1) {
          mZ = zShore - 1;
        }
      }

      Vertex M = tin.splitEdge(edge, mZ, false);
      M.setSynthetic(true);
      M.setAuxiliaryIndex(1);
      fixVertices.add(M);

      //  mean depth(A, M, C) is (0 + zShore-mZ + 0)/3
      //  mean depth(M, B, C) is (zShore-mZ + 0 + 0)/3
      //  so mean depth for both triangles is equal.
      //  the area of both split triangles is equal and given by area/2
      //  so volumes of both split triangles is equal
      //  so the volume is  2 * (area/2)*(zShore-mZ)/3
      double meanDepth = (zShore - mZ) / 3.0;
      double volume = area * meanDepth;
      remediatedArea += area;
      remediatedVolume += volume;

    }

    return fixVertices;
  }

  /**
   * Gets a count for the number of remediations that were performed.
   *
   * @return a positive integer value
   */
  int getRemediationCount() {
    return nRemediations;
  }

  /**
   * Gets the area of the triangles that were remediated.
   *
   * @return the area of the remediated triangles
   */
  double getRemediatedArea() {
    return remediatedArea;
  }

  /**
   * Gets the post-remediation volume contribution of the triangles that were
   * adjusted.
   *
   * @return the remediatedVolume
   */
  double getRemediatedVolume() {
    return remediatedVolume;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy