001/*
002 * Copyright (c) 1998-2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: welker $'
006 * '$Date: 2010-05-06 05:21:26 +0000 (Thu, 06 May 2010) $' 
007 * '$Revision: 24234 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029
030package org.geon;
031
032import java.awt.Point;
033import java.io.BufferedReader;
034import java.io.BufferedWriter;
035import java.io.File;
036import java.io.FileReader;
037import java.io.FileWriter;
038import java.io.IOException;
039
040import nl.skybound.awt.DoublePolygon;
041import ptolemy.actor.TypedAtomicActor;
042import ptolemy.actor.TypedIOPort;
043import ptolemy.data.ObjectToken;
044import ptolemy.data.StringToken;
045import ptolemy.data.type.BaseType;
046import ptolemy.gui.MessageHandler;
047import ptolemy.kernel.CompositeEntity;
048import ptolemy.kernel.util.IllegalActionException;
049import ptolemy.kernel.util.NameDuplicationException;
050
051//////////////////////////////////////////////////////////////////////////
052//// PointInPolygon
053/**
054 * This actor receives an array of polygon points and populates them in a
055 * polygon object it also receives a classification point. The actor outputs
056 * whether the point is contained in the polygon along with the polygon
057 * coordinates for display purposes.
058 * 
059 * @author Efrat Jaeger
060 * @version $Id: PointinPolygon.java 24234 2010-05-06 05:21:26Z welker $
061 * @since Ptolemy II 3.0.2
062 */
063public class PointinPolygon extends TypedAtomicActor {
064
065        /**
066         * Construct an actor with the given container and name.
067         * 
068         * @param container
069         *            The container.
070         * @param name
071         *            The name of this actor.
072         * @exception IllegalActionException
073         *                If the actor cannot be contained by the proposed
074         *                container.
075         * @exception NameDuplicationException
076         *                If the container already has an actor with this name.
077         */
078        public PointinPolygon(CompositeEntity container, String name)
079                        throws NameDuplicationException, IllegalActionException {
080
081                super(container, name);
082
083                // Set the type constraint.
084                region = new TypedIOPort(this, "region", false, true);
085                region.setTypeEquals(BaseType.STRING);
086                toBrowser = new TypedIOPort(this, "toBrowser", false, true);
087                toBrowser.setTypeEquals(BaseType.STRING);
088                point = new TypedIOPort(this, "point", true, false); // input point
089                point.setTypeEquals(BaseType.GENERAL);
090                polygonRegions = new TypedIOPort(this, "polygonRegions", true, false); // Polygon
091                                                                                                                                                                // coordinates
092                                                                                                                                                                // and
093                                                                                                                                                                // regions
094                polygonRegions.setTypeEquals(BaseType.GENERAL);
095
096                _attachText("_iconDescription", "<svg>\n"
097                                + "<polygon points=\"-15,-2 0,-15 15,-2 11,15 -11,15\" "
098                                + "style=\"fill:white\"/>\n"
099                                + "<circle cx=\"3\" cy=\"4\" r=\"1\""
100                                + "style=\"fill:black\"/>\n" + "</svg>\n");
101
102        }
103
104        // /////////////////////////////////////////////////////////////////
105        // // ports and parameters ////
106
107        /**
108         * A classification point.
109         */
110        public TypedIOPort point;
111
112        /**
113         * A set of polygons and their region names.
114         */
115        public TypedIOPort polygonRegions;
116
117        /**
118         * The point's region.
119         */
120        public TypedIOPort region;
121
122        /**
123         * A URL for display the point in the regions.
124         */
125        public TypedIOPort toBrowser;
126
127        /**
128         * Receive a set of polygons and a classification point and returns the
129         * point region along with a URL for browser display of the point in the
130         * polygon.
131         * 
132         * @exception IllegalActionException
133         *                If there's no director.
134         */
135        public void fire() throws IllegalActionException {
136                super.fire();
137                int layer = 1;
138                while (true) {
139                        if (polygonRegions.hasToken(0) && point.hasToken(0)) {
140                                ObjectToken obj1 = (ObjectToken) polygonRegions.get(0);
141                                PolygonUtil polygons[] = (PolygonUtil[]) obj1.getValue();
142                                ObjectToken obj2 = (ObjectToken) point.get(0);
143                                Point p = (Point) obj2.getValue();
144                                x = p.getX();
145                                y = p.getY();
146                                // System.out.println("pointInPolygon point: {" + x + " , " + y
147                                // + "}");
148                                for (int j = 0; j < polygons.length; j++) {
149                                        DoublePolygon P = polygons[j].getPolygon();
150                                        // for (int i=0; i<P.npoints;i++)
151                                        // System.out.println("{" + P.xpoints[i] + " , " +
152                                        // P.ypoints[i] + "}");
153                                        arrayLen = P.npoints;
154                                        String _region = polygons[j].getRegion();
155                                        // System.out.println("region = " + _region);
156                                        if (_isPolygonVertex(P, x, y) || _onPolygonEdge(P, x, y)
157                                                        || P.contains(x, y)) {
158                                                result = _region; // FIX ME!!! TAKE CARE OF MULTIPLE
159                                                                                        // REGIONS AND NO REGION!!!
160                                        }
161                                }
162
163                                // get the working directory.
164                                String _keplerPath = System.getProperty("user.dir");
165
166                                String displayFile = _keplerPath + "/lib/testdata/geon/layer"
167                                                + layer + ".svg";
168                                _addRegionToSVG(displayFile, result);
169                                region.broadcast(new StringToken(result));
170                                if (layer == 1 && !result.trim().startsWith("diorite")) // FIX
171                                                                                                                                                // ME!!
172                                                                                                                                                // for
173                                                                                                                                                // now
174                                                                                                                                                // only
175                                                                                                                                                // diorite
176                                                                                                                                                // has a
177                                                                                                                                                // second
178                                                                                                                                                // level.
179                                        layer++;
180                                // System.out.println("file to display: " + displayFile);
181                                toBrowser.broadcast(new StringToken(displayFile)); // FIX ME!!!
182                                                                                                                                        // ADD THE
183                                                                                                                                        // FILE TO
184                                                                                                                                        // SHOW!!!
185                                layer++;
186                                if (layer > 2)
187                                        break;
188                        }
189                }
190        }
191
192        /**
193         * Post fire the actor. Return false to indicate that the process has
194         * finished. If it returns true, the process will continue indefinitely.
195         */
196        public boolean postfire() {
197                return false;
198        }
199
200        // /////////////////////////////////////////////////////////////////
201        // // private methods ////
202
203        /*
204         * Checking whether the given point is one of the polygon's vertices.
205         */
206        private boolean _isPolygonVertex(DoublePolygon P, double x, double y) {
207                for (int i = 0; i < arrayLen; i++) {
208                        if (P.xpoints[i] == x && P.ypoints[i] == y)
209                                return true;
210                }
211                return false;
212        }
213
214        /*
215         * Checking whether the given point is one of the polygon's edges.
216         */
217        private boolean _onPolygonEdge(DoublePolygon P, double x, double y) {
218                double x1, x2, y1, y2;
219                for (int i = 0; i < arrayLen; i++) {
220                        x1 = P.xpoints[i];
221                        x2 = P.xpoints[(i + 1) % arrayLen];
222                        y1 = P.ypoints[i];
223                        y2 = P.ypoints[(i + 1) % arrayLen];
224                        if (((x1 <= x && x <= x2) || (x2 <= x && x <= x1)) && // x and y are
225                                                                                                                                        // between
226                                                                                                                                        // x1,x2 and
227                                                                                                                                        // y1,y2
228                                        ((y1 <= y && y <= y2) || (y2 <= y && y <= y1))) {
229                                if (((y - y1) / (x - x1)) == ((y - y2) / (x - x2)))
230                                        return true;
231                        }
232                }
233                return false;
234        }
235
236        /*
237         * Adding the classification point to the SVG file for display purposes.
238         */
239        private void _addRegionToSVG(String svgFile, String region) {
240                try {
241                        // System.out.println("SVG File: " + svgFile);
242                        File svg = new File(svgFile);
243                        BufferedReader br = new BufferedReader(new FileReader(svg));
244                        String line;
245                        String toFile = "";
246                        String extraLine;
247                        if (region.length() > 20) {
248                                int tmp = result.indexOf(" ", 15);
249                                extraLine = "<text x= '315' y='70' fill='blue' text-anchor='middle' style='font-size: 12pt; font-family: serif; ' >"
250                                                + region.substring(0, tmp) + "</text>";
251                                extraLine += "<text x= '315' y='90' fill='blue' text-anchor='middle' style='font-size: 12pt; font-family: serif; ' >"
252                                                + region.substring(tmp + 1) + "</text>";
253                        } else {
254                                extraLine = "<text x= '315' y='70' fill='blue' text-anchor='middle' style='font-size: 12pt; font-family: serif; ' >"
255                                                + region + "</text>";
256                        }
257                        // System.out.println("Extra line" + extraLine);
258                        while ((line = br.readLine()) != null) {
259                                int ind = line.toLowerCase().indexOf("<text");
260                                if (ind != -1) {
261                                        // System.out.println("Inside extra line");
262                                        toFile += line.substring(0, ind) + "\n";
263                                        toFile += extraLine + "\n";
264                                        toFile += line.substring(ind) + "\n";
265                                } else
266                                        toFile += line + "\n";
267                        }
268                        br.close();
269
270                        // System.out.println(toFile);
271                        BufferedWriter out = new BufferedWriter(new FileWriter(svg));
272                        out.write(toFile);
273                        out.close();
274                } catch (IOException e) {
275                        MessageHandler.error("Error opening file", e);
276                }
277        }
278
279        // /////////////////////////////////////////////////////////////////
280        // // private members ////
281
282        private double x, y;
283        private String result, id;
284        private int arrayLen;
285}