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 ScaledNoder(Noder noder, double scaleFactor)46 public ScaledNoder(Noder noder, double scaleFactor) { 47 this(noder, scaleFactor, 0, 0); 48 } 49 ScaledNoder(Noder noder, double scaleFactor, double offsetX, double offsetY)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 isIntegerPrecision()57 public boolean isIntegerPrecision() { return scaleFactor == 1.0; } 58 getNodedSubstrings()59 public Collection getNodedSubstrings() 60 { 61 Collection splitSS = noder.getNodedSubstrings(); 62 if (isScaled) rescale(splitSS); 63 return splitSS; 64 } 65 computeNodes(Collection inputSegStrings)66 public void computeNodes(Collection inputSegStrings) 67 { 68 Collection intSegStrings = inputSegStrings; 69 if (isScaled) 70 intSegStrings = scale(inputSegStrings); 71 noder.computeNodes(intSegStrings); 72 } 73 scale(Collection segStrings)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 scale(Coordinate[] pts)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 rescale(Collection segStrings)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 rescale(Coordinate[] pts)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