Class ScaledNoder

  1 /*
  2  * Copyright (c) 2016 Vivid Solutions.
  3  *
  4  * All rights reserved. This program and the accompanying materials
  5  * are made available under the terms of the Eclipse Public License 2.0
  6  * and Eclipse Distribution License v. 1.0 which accompanies this distribution.
  7  * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html
  8  * and the Eclipse Distribution License is available at
  9  *
 10  * http://www.eclipse.org/org/documents/edl-v10.php.
 11  */
 12  
 13 package org.locationtech.jts.noding;
 14  
 15 import java.util.ArrayList;
 16 import java.util.Collection;
 17 import java.util.Iterator;
 18 import java.util.List;
 19  
 20 import org.locationtech.jts.geom.Coordinate;
 21 import org.locationtech.jts.geom.CoordinateArrays;
 22  
 23 /**
 24  * Wraps a {@link Noder} and transforms its input
 25  * into the integer domain.
 26  * This is intended for use with Snap-Rounding noders,
 27  * which typically are only intended to work in the integer domain.
 28  * Offsets can be provided to increase the number of digits of available precision.
 29  * <p>
 30  * Clients should be aware that rescaling can involve loss of precision,
 31  * which can cause zero-length line segments to be created.
 32  * These in turn can cause problems when used to build a planar graph.
 33  * This situation should be checked for and collapsed segments removed if necessary.
 34  *
 35  * @version 1.7
 36  */
 37 public class ScaledNoder
 38     implements Noder
 39 {
 40   private Noder noder;
 41   private double scaleFactor;
 42   private double offsetX;
 43   private double offsetY;
 44   private boolean isScaled = false;
 45  
 46   public ScaledNoder(Noder noder, double scaleFactor) {
 47     this(noder, scaleFactor, 00);
 48   }
 49  
 50   public ScaledNoder(Noder noder, double scaleFactor, double offsetX, double offsetY) {
 51     this.noder = noder;
 52     this.scaleFactor = scaleFactor;
 53     // no need to scale if input precision is already integral
 54     isScaled = ! isIntegerPrecision();
 55   }
 56  
 57   public boolean isIntegerPrecision() { return scaleFactor == 1.0; }
 58  
 59   public Collection getNodedSubstrings()
 60   {
 61     Collection splitSS = noder.getNodedSubstrings();
 62     if (isScaled) rescale(splitSS);
 63     return splitSS;
 64   }
 65  
 66   public void computeNodes(Collection inputSegStrings)
 67   {
 68     Collection intSegStrings = inputSegStrings;
 69     if (isScaled)
 70       intSegStrings = scale(inputSegStrings);
 71     noder.computeNodes(intSegStrings);
 72   }
 73  
 74   private Collection scale(Collection segStrings)
 75   {
 76     List nodedSegmentStrings = new ArrayList(segStrings.size());
 77     for (Iterator i = segStrings.iterator(); i.hasNext(); ) {
 78       SegmentString ss = (SegmentString) i.next();
 79       nodedSegmentStrings.add(new NodedSegmentString(scale(ss.getCoordinates()), ss.getData()));
 80     }
 81     return nodedSegmentStrings;
 82   }
 83  
 84   private Coordinate[] scale(Coordinate[] pts)
 85   {
 86     Coordinate[] roundPts = new Coordinate[pts.length];
 87     for (int i = 0; i < pts.length; i++) {
 88       roundPts[i] = new Coordinate(
 89           Math.round((pts[i].x - offsetX) * scaleFactor),
 90           Math.round((pts[i].y - offsetY) * scaleFactor),
 91           pts[i].getZ()
 92         );
 93     }
 94     Coordinate[] roundPtsNoDup = CoordinateArrays.removeRepeatedPoints(roundPts);
 95     return roundPtsNoDup;
 96   }
 97  
 98   //private double scale(double val) { return (double) Math.round(val * scaleFactor); }
 99  
100   private void rescale(Collection segStrings)
101   {
102     for (Iterator i = segStrings.iterator(); i.hasNext(); ) {
103       SegmentString ss = (SegmentString) i.next();
104       rescale(ss.getCoordinates());
105     }
106   }
107  
108   private void rescale(Coordinate[] pts)
109   {
110     for (int i = 0; i < pts.length; i++) {
111       pts[i].x = pts[i].x / scaleFactor + offsetX;
112       pts[i].y = pts[i].y / scaleFactor + offsetY;
113     }
114  
115     if (pts.length == 2 && pts[0].equals2D(pts[1])) {
116       System.out.println(pts);
117     }
118   }
119  
120   //private double rescale(double val) { return val / scaleFactor; }
121 }
122