1 /* 2 * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.marlin; 27 28 import com.sun.javafx.geom.PathConsumer2D; 29 30 public final class PathSimplifier implements PathConsumer2D { 31 32 // distance threshold in pixels (device) 33 private static final float PIX_THRESHOLD = MarlinProperties.getPathSimplifierPixelTolerance(); 34 // squared tolerance in pixels 35 private static final float SQUARE_TOLERANCE = PIX_THRESHOLD * PIX_THRESHOLD; 36 37 // members: 38 private PathConsumer2D delegate; 39 // current reference point 40 private float cx, cy; 41 // flag indicating if the given point was skipped 42 private boolean skipped; 43 // last skipped point 44 private float sx, sy; 45 46 PathSimplifier() { 47 } 48 49 public PathSimplifier init(final PathConsumer2D delegate) { 50 this.delegate = delegate; 51 skipped = false; 52 return this; // fluent API 53 } 54 55 private void finishPath() { 56 if (skipped) { 57 _lineTo(sx, sy); 58 } 59 } 60 61 @Override 62 public void pathDone() { 63 finishPath(); 64 delegate.pathDone(); 65 } 66 67 @Override 68 public void closePath() { 69 finishPath(); 70 delegate.closePath(); 71 } 72 73 @Override 74 public void moveTo(final float xe, final float ye) { 75 finishPath(); 76 delegate.moveTo(xe, ye); 77 cx = xe; 78 cy = ye; 79 } 80 81 @Override 82 public void lineTo(final float xe, final float ye) { 83 // Test if segment is too small: 84 float dx = (xe - cx); 85 float dy = (ye - cy); 86 87 if ((dx * dx + dy * dy) <= SQUARE_TOLERANCE) { 88 skipped = true; 89 sx = xe; 90 sy = ye; 91 return; 92 } 93 _lineTo(xe, ye); 94 } 95 96 private void _lineTo(final float xe, final float ye) { 97 delegate.lineTo(xe, ye); 98 cx = xe; 99 cy = ye; 100 skipped = false; 101 } 102 103 @Override 104 public void quadTo(final float x1, final float y1, 105 final float xe, final float ye) 106 { 107 // Test if curve is too small: 108 float dx = (xe - cx); 109 float dy = (ye - cy); 110 111 if ((dx * dx + dy * dy) <= SQUARE_TOLERANCE) { 112 // check control points P1: 113 dx = (x1 - cx); 114 dy = (y1 - cy); 115 116 if ((dx * dx + dy * dy) <= SQUARE_TOLERANCE) { 117 skipped = true; 118 sx = xe; 119 sy = ye; 120 return; 121 } 122 } 123 delegate.quadTo(x1, y1, xe, ye); 124 cx = xe; 125 cy = ye; 126 skipped = false; 127 } 128 129 @Override 130 public void curveTo(final float x1, final float y1, 131 final float x2, final float y2, 132 final float xe, final float ye) 133 { 134 // Test if curve is too small: 135 float dx = (xe - cx); 136 float dy = (ye - cy); 137 138 if ((dx * dx + dy * dy) <= SQUARE_TOLERANCE) { 139 // check control points P1: 140 dx = (x1 - cx); 141 dy = (y1 - cy); 142 143 if ((dx * dx + dy * dy) <= SQUARE_TOLERANCE) { 144 // check control points P2: 145 dx = (x2 - cx); 146 dy = (y2 - cy); 147 148 if ((dx * dx + dy * dy) <= SQUARE_TOLERANCE) { 149 skipped = true; 150 sx = xe; 151 sy = ye; 152 return; 153 } 154 } 155 } 156 delegate.curveTo(x1, y1, x2, y2, xe, ye); 157 cx = xe; 158 cy = ye; 159 skipped = false; 160 } 161 }