/******************************************************************************* * Copyright 2010 Simon Mieth * * 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. ******************************************************************************/ package org.kabeja.entities.util; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.kabeja.entities.Hatch; import org.kabeja.math.Bounds; import org.kabeja.math.MathUtils; import org.kabeja.math.ParametricLine; import org.kabeja.math.Point3D; import org.kabeja.math.Vector; /** * @author <a href="mailto:simon.mieth@gmx.de>Simon Mieth</a> * */ public class HatchLineIterator implements Iterator<HatchLineSegment>{ public static final double LIMIT = 0.00001; protected double angle; protected Bounds hatchBounds; protected HatchLineFamily pattern; protected double length; protected Vector v; protected Vector r; protected List bounderyEdges; protected ParametricLine patternLine; protected double tmin = Double.POSITIVE_INFINITY; protected double tmax = Double.NEGATIVE_INFINITY; protected double walkingLength; protected double currentWalkingStep = 0; public HatchLineIterator(Hatch hatch, HatchLineFamily pattern) { this.angle = Math.toRadians(pattern.getRotationAngle()); this.hatchBounds = hatch.getBounds(); this.length = pattern.getLength(); this.bounderyEdges = new ArrayList(); // edge 0 Point3D start = new Point3D(this.hatchBounds.getMinimumX(), this.hatchBounds.getMaximumY(), 0); Point3D end = new Point3D(this.hatchBounds.getMinimumX(), this.hatchBounds.getMinimumY(), 0); this.bounderyEdges.add(new ParametricLine(start, MathUtils.getVector(start, end))); // edge 1 start = new Point3D(this.hatchBounds.getMinimumX(), this.hatchBounds.getMinimumY(), 0); end = new Point3D(this.hatchBounds.getMaximumX(), this.hatchBounds.getMinimumY(), 0); this.bounderyEdges.add(new ParametricLine(start, MathUtils.getVector(start, end))); // edge 2 start = new Point3D(this.hatchBounds.getMaximumX(), this.hatchBounds.getMinimumY(), 0); end = new Point3D(this.hatchBounds.getMaximumX(), this.hatchBounds.getMaximumY(), 0); this.bounderyEdges.add(new ParametricLine(start, MathUtils.getVector(start, end))); // edge 3 start = new Point3D(this.hatchBounds.getMaximumX(), this.hatchBounds.getMaximumY(), 0); end = new Point3D(this.hatchBounds.getMinimumX(), this.hatchBounds.getMaximumY(), 0); this.bounderyEdges.add(new ParametricLine(start, MathUtils.getVector(start, end))); this.pattern = pattern; this.initialize(); } public boolean hasNext() { return this.currentWalkingStep <= this.walkingLength; } protected void initialize() { // setup a length // this can happen on solid lines if (this.length == 0) { this.length = 1; } // first get the center point of the bound rectangle Point3D center = new Point3D(); center.setX(this.hatchBounds.getMinimumX() + (this.hatchBounds.getWidth() / 2)); center.setY(this.hatchBounds.getMinimumY() + (this.hatchBounds.getHeight() / 2)); center.setZ(0); this.r = new Vector(); if (Math.abs(this.pattern.getOffsetY()) < LIMIT) { this.r.setY(0); } else { this.r.setY(this.pattern.getOffsetY()); } if (Math.abs(this.pattern.getOffsetX()) < LIMIT) { this.r.setX(0); } else { this.r.setX(this.pattern.getOffsetX()); } // create the direction vector of the line family this.v = new Vector(); this.v.setX(this.length * Math.cos(this.angle)); this.v.setY(this.length * Math.sin(this.angle)); if (Math.abs(this.v.getX()) < LIMIT) { this.v.setX(0); } if (Math.abs(this.v.getY()) < LIMIT) { this.v.setY(0); } // we will now find the next raster point near the center point double[] para = this.getRasterValues(center.getX(), center.getY()); center = this.getPoint(Math.round(para[0]), Math.round(para[1])); // we create now our walking line this.patternLine = new ParametricLine(center, this.r); this.calculateIntersection(this.hatchBounds.getMinimumX(), this.hatchBounds.getMaximumY()); this.calculateIntersection(this.hatchBounds.getMinimumX(), this.hatchBounds.getMinimumY()); this.calculateIntersection(this.hatchBounds.getMaximumX(), this.hatchBounds.getMinimumY()); this.calculateIntersection(this.hatchBounds.getMaximumX(), this.hatchBounds.getMaximumY()); // the minimum point is our starting point this.tmin = Math.floor(this.tmin); this.tmax = Math.ceil(this.tmax); Point3D p = this.patternLine.getPointAt(this.tmin); this.patternLine.setStartPoint(p); this.walkingLength = Math.ceil(Math.abs(this.tmax - this.tmin)); } protected void calculateIntersection(double x, double y) { Point3D s = new Point3D(x, y, 0); ParametricLine line = new ParametricLine(s, this.v); double t = this.patternLine.getIntersectionParameter(line); if (t < this.tmin) { this.tmin = t; } if (t > this.tmax) { this.tmax = t; } } /** * calculate the m and n raster values of a given point. * * @return the raster values, where v[0]=m and v[1]=n */ protected double[] getRasterValues(double x, double y) { double[] v = new double[2]; if (this.r.getX() == 0.0) { v[0] = (x - this.pattern.getBaseX()) / this.v.getX(); v[1] = (y - this.pattern.getBaseY() - (this.v.getY() * v[0])) / this.r.getY(); } else if (this.r.getY() == 0.0) { v[0] = (y - this.pattern.getBaseY()) / this.v.getY(); v[1] = (x - this.pattern.getBaseX()) / this.r.getX(); } else if (this.v.getX() == 0) { v[1] = (x - this.pattern.getBaseX()) / this.r.getX(); v[0] = (y - this.pattern.getBaseY() - (this.r.getY() * v[1])) / this.v.getY(); } else if (this.v.getY() == 0.0) { v[1] = (y - this.pattern.getBaseY()) / this.r.getY(); v[0] = (x - this.pattern.getBaseX() - (this.r.getX() * v[1])) / this.v.getX(); } else { // a helper variable double a = this.r.getY() / this.r.getX(); v[0] = (y - this.pattern.getBaseY() - (x * a) + (this.pattern.getBaseX() * a)) / (this.v.getY() - (a * this.v.getX())); v[1] = (x - this.pattern.getBaseX() - (this.v.getX() * v[0])) / this.r.getX(); } return v; } public HatchLineSegment next() { Point3D p = this.patternLine.getPointAt(this.currentWalkingStep); ParametricLine line = new ParametricLine(p, this.v); // get the next intersection of Iterator i = this.bounderyEdges.iterator(); List points = new ArrayList(); while (i.hasNext()) { ParametricLine edge = (ParametricLine) i.next(); double t = edge.getIntersectionParameter(line); if ((t >= 0) && (t < 1)) { points.add(edge.getPointAt(t)); } } double startL = 0; double l = 0; if (points.size() == 2) { Point3D start = (Point3D) points.get(0); double startT = line.getParameter(start); Point3D end = (Point3D) points.get(1); double endT = line.getParameter(end); startL = 0; if (startT > endT) { line.setStartPoint(end); startL = Math.abs(endT - Math.floor(endT)) * this.length; } else { line.setStartPoint(start); startL = Math.abs(startT - Math.floor(startT)) * this.length; } l = Math.abs(endT - startT) * this.length; } line.setDirectionVector(MathUtils.normalize(this.v)); HatchLineSegment segment = new HatchLineSegment(line, l, startL, this.pattern.getPattern()); this.currentWalkingStep++; return segment; } public void remove() { // we do nothing here } protected Point3D getPoint(double m, double n) { Point3D p = new Point3D(); p.setX((n * this.r.getX()) + this.pattern.getBaseX() + (this.v.getX() * m)); p.setY((n * this.r.getY()) + this.pattern.getBaseY() + (this.v.getY() * m)); return p; } }