Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I've solved the problem:</p> <p>First, find all the line segments that constrain the <code>Area</code>. I've written code to do that <a href="https://stackoverflow.com/questions/8144156/using-pathiterator-to-return-all-line-segments-that-constrain-an-area/8145796#8145796">on a different answer</a>.</p> <p>Then, it's just a matter of iterating through each line segment, and recording the point on the segment that's closest to the entity's desired point. Store these in the data structure of your choice (e.g., an <code>ArrayList</code>).</p> <p>See: <a href="https://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment">Shortest distance between a point and a line segment</a></p> <p>Lastly, determine which of the points is closest to the desired point. Voilà!</p> <p>Here's a demonstration: </p> <pre><code>import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.geom.Area; import java.awt.geom.Ellipse2D; import java.awt.geom.Line2D; import java.awt.geom.Path2D; import java.awt.geom.PathIterator; import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.Random; import javax.swing.JFrame; public class AreaTest extends JFrame{ private static final long serialVersionUID = -2221432546854106311L; Area area = new Area(); ArrayList&lt;Line2D.Double&gt; areaSegments = new ArrayList&lt;Line2D.Double&gt;(); Point2D.Double insidePoint = new Point2D.Double(225, 225); Point2D.Double closestPoint = new Point2D.Double(-1, -1); Point2D.Double bestPoint = new Point2D.Double(-1, -1); ArrayList&lt;Point2D.Double&gt; closestPointList = new ArrayList&lt;Point2D.Double&gt;(); AreaTest() { Path2D.Double triangle = new Path2D.Double(); Random random = new Random(); // Draw three random triangles for (int i = 0; i &lt; 3; i++) { triangle.moveTo(random.nextInt(400) + 50, random.nextInt(400) + 50); triangle.lineTo(random.nextInt(400) + 50, random.nextInt(400) + 50); triangle.lineTo(random.nextInt(400) + 50, random.nextInt(400) + 50); triangle.closePath(); area.add(new Area(triangle)); triangle.reset(); } // Place a point inside the area if (!area.contains(insidePoint)); { while (!area.contains(insidePoint)) { insidePoint.setLocation(random.nextInt(400) + 50, random.nextInt(400) + 50); } } // Note: we're storing double[] and not Point2D.Double ArrayList&lt;double[]&gt; areaPoints = new ArrayList&lt;double[]&gt;(); double[] coords = new double[6]; for (PathIterator pi = area.getPathIterator(null); !pi.isDone(); pi.next()) { // Because the Area is composed of straight lines int type = pi.currentSegment(coords); // We record a double array of {segment type, x coord, y coord} double[] pathIteratorCoords = {type, coords[0], coords[1]}; areaPoints.add(pathIteratorCoords); } double[] start = new double[3]; // To record where each polygon starts for (int i = 0; i &lt; areaPoints.size(); i++) { // If we're not on the last point, return a line from this point to the next double[] currentElement = areaPoints.get(i); // We need a default value in case we've reached the end of the ArrayList double[] nextElement = {-1, -1, -1}; if (i &lt; areaPoints.size() - 1) { nextElement = areaPoints.get(i + 1); } // Make the lines if (currentElement[0] == PathIterator.SEG_MOVETO) { start = currentElement; // Record where the polygon started to close it later } if (nextElement[0] == PathIterator.SEG_LINETO) { areaSegments.add( new Line2D.Double( currentElement[1], currentElement[2], nextElement[1], nextElement[2] ) ); } else if (nextElement[0] == PathIterator.SEG_CLOSE) { areaSegments.add( new Line2D.Double( currentElement[1], currentElement[2], start[1], start[2] ) ); } } // Calculate the nearest point on the edge for (Line2D.Double line : areaSegments) { // From: https://stackoverflow.com/questions/6176227 double u = ((insidePoint.getX() - line.x1) * (line.x2 - line.x1) + (insidePoint.getY() - line.y1) * (line.y2 - line.y1)) / ((line.x2 - line.x1) * (line.x2 - line.x1) + (line.y2 - line.y1) * (line.y2 - line.y1)); double xu = line.x1 + u * (line.x2 - line.x1); double yu = line.y1 + u * (line.y2 - line.y1); if (u &lt; 0) { closestPoint.setLocation(line.getP1()); } else if (u &gt; 1) { closestPoint.setLocation(line.getP2()); } else { closestPoint.setLocation(xu, yu); } closestPointList.add((Point2D.Double) closestPoint.clone()); if (closestPoint.distance(insidePoint) &lt; bestPoint.distance(insidePoint)) { bestPoint.setLocation(closestPoint); } } setSize(new Dimension(500, 500)); setLocationRelativeTo(null); // To center the JFrame on screen setDefaultCloseOperation(EXIT_ON_CLOSE); setResizable(false); setVisible(true); } public void paint(Graphics g) { // Fill the area Graphics2D g2d = (Graphics2D) g; g.setColor(Color.lightGray); g2d.fill(area); // Draw the border line by line g.setColor(Color.black); for (Line2D.Double line : areaSegments) { g2d.draw(line); } // Draw the inside point g.setColor(Color.red); g2d.fill( new Ellipse2D.Double( insidePoint.getX() - 3, insidePoint.getY() - 3, 6, 6 ) ); // Draw the other close points for (Point2D.Double point : closestPointList) { g.setColor(Color.black); g2d.fill( new Ellipse2D.Double( point.getX() - 3, point.getY() - 3, 6, 6 ) ); } // Draw the outside point g.setColor(Color.green); g2d.fill( new Ellipse2D.Double( bestPoint.getX() - 3, bestPoint.getY() - 3, 6, 6 ) ); } public static void main(String[] args) { new AreaTest(); } } </code></pre> <p>Here's the result: </p> <p><img src="https://i.stack.imgur.com/WkveB.png" alt="enter image description here"></p> <p>And again: </p> <p><img src="https://i.stack.imgur.com/StFt7.png" alt="enter image description here"></p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload