001    /*
002     * SimuCS - Simulator to use with Classifier Systems 
003     * MSc project - Oxford University 
004     * by Benoit Isaac - Summer 2005
005     */
006    
007    package simuLCS;
008    import java.awt.Color;
009    import java.awt.Graphics2D;
010    import java.awt.geom.Point2D;
011    
012    /**
013     * Handles all the functions for 2D Vectors.
014     * @author Benoit
015     * 
016     */
017    public class Vector2D {
018    
019            private double x, y;
020    
021            /**
022             * Creates a  vector (0,0)
023             *
024             */
025            public Vector2D() {
026                    x = 0.0;
027                    y = 0.0;
028            }
029    
030            /**
031             * Creates a vector (xp,yp)
032             * @param xp
033             * @param yp
034             */
035            public Vector2D(double xp, double yp) {
036                    x = xp;
037                    y = yp;
038            }
039    
040            /**
041             * Creates a vector between (0,0) and the given point
042             * @param p
043             */
044            public Vector2D(Point2D p) {
045                    x = p.getX();
046                    y = p.getY();
047            }
048    
049            /**
050             * Creates the vector between two given points
051             * @param p1
052             * @param p2
053             */
054            public Vector2D(Point2D p1, Point2D p2) {
055                    x = p2.getX() - p1.getX();
056                    y = p2.getY() - p1.getY();
057            }
058    
059            /**
060             * Creates a clone of a given vector
061             * @param v
062             */
063            public Vector2D(Vector2D v) {
064                    x = v.getX();
065                    y = v.getY();
066            }
067    
068            /**
069             * Add the given vector to this vector (it modifies the vector)
070             * @param v
071             */
072            public void add(Vector2D v) {
073                    x = x + v.getX();
074                    y = y + v.getY();
075            }
076    
077            /**
078             * Change the vector into its opposite
079             *
080             */
081            public void opposite() {
082                    x = -x;
083                    y = -y;
084            }
085    
086            /**
087             * Change the scale of the vector by multiplying its coordinates by a contant
088             * @param d
089             */
090            public void multiplyByConstant(double d) {
091                    x = d * x;
092                    y = d * y;
093            }
094    
095            /**
096             * Set the Vector to the unit vector between the two points
097             * the previous values of the Vector are lost.
098             * @param p1
099             * @param p2
100             */
101            public void setUnitVector(Point2D p1, Point2D p2) {
102                    double xv = p2.getX() - p1.getX();
103                    double yv = p2.getY() - p1.getY();
104                    double dist = Math.sqrt(xv * xv + yv * yv);
105                    x = xv / dist;
106                    y = yv / dist;
107            }
108            
109            /**
110             * Get the norm of the Vector
111             * @return
112             */
113            public double getNorm(){
114                    double norm = Math.sqrt((x*x) + (y*y));
115                    return norm;
116            }
117    
118            /**
119             * @return
120             */
121            public double getX() {
122                    return x;
123            }
124    
125            /**
126             * @return
127             */
128            public double getY() {
129                    return y;
130            }
131    
132            /**
133             * @param d
134             */
135            public void setX(double d) {
136                    x = d;
137            }
138    
139            /**
140             * @param d
141             */
142            public void setY(double d) {
143                    y = d;
144            }
145    
146            public String toString() {
147                    return "Vector: x:" + getX() + " y:" + getY();
148            }
149    
150            /**
151             * Paints the vector (useful for debugging)
152             * @param p
153             * @param g
154             * @param c
155             */
156            public void paint(Point2D p, Graphics2D g, Color c) {
157                    Color oldc = g.getColor();
158                    int x1 = (int) p.getX();
159                    int y1 = (int) p.getY();
160                    int x2 = x1 + (int) getX();
161                    int y2 = y1 + (int) getY();
162                    g.setColor(c);
163    
164                    g.drawLine(x1, y1, x2, y2);
165                    g.setColor(oldc);
166            }
167    
168            /**
169             * Get a perpendicular vector, on the left
170             * @return
171             */
172            public Vector2D getNormalLeft() {
173                    return new Vector2D(this.getY(), -this.getX());
174            }
175    
176            /**
177             * Correct the vector so that it doesn't bring the Entity outside the Arena.
178             * @param v
179             * @param a
180             * @param me
181             * @return
182             */
183            public static Vector2D getCorrectedVector(
184                    Vector2D movVector,
185                    Arena a,
186                    Entity me,
187                    Graphics2D g) {
188    
189                    double CLOSEST_DISTANCE_TO_WALL = 4;
190                    double SCALE_MOVEMENT = 15;
191    
192                    Vector2D r = new Vector2D();
193    //              movVector.paint(me.getCoord(), g, Color.RED);
194    
195                    double nextX = me.getCoord().getX() + movVector.getX();
196                    double nextY = me.getCoord().getY() + movVector.getY();
197                    Point2D nextPosition = new Point2D.Double(nextX, nextY);
198    
199    //              g.setColor(Color.RED);
200    //              g.fillOval(
201    //                      (int) nextPosition.getX() - 2,
202    //                      (int) nextPosition.getY() - 2,
203    //                      4,
204    //                      4);
205    
206                    if ((a.isInside(nextX, nextY, me.getRadiusBody()))
207                            && (a.distanceTo(nextPosition) > CLOSEST_DISTANCE_TO_WALL)) {
208                            // next position inside arena, it's ok
209                            r.add(movVector);
210                    } else {
211                            // next position outside, we need to correct
212                            Vector2D vNotTooBig = new Vector2D(me.getCoord(), nextPosition);
213                            vNotTooBig.add(vNotTooBig.getNormalLeft());
214                            
215                            double withNormLeftX = me.getCoord().getX() + vNotTooBig.getX();
216                            double withNormLeftY = me.getCoord().getY() + vNotTooBig.getY();
217                            
218                            Point2D withNormLeft = new Point2D.Double(withNormLeftX,
219                                    withNormLeftY);
220                            
221                            vNotTooBig.setUnitVector(me.getCoord(), withNormLeft);
222                            vNotTooBig.multiplyByConstant(SCALE_MOVEMENT);
223    
224                            double nextXnotTooBig = me.getCoord().getX() + vNotTooBig.getX();
225                            double nextYnotTooBig = me.getCoord().getY() + vNotTooBig.getY();
226    
227                            Point2D nextPosNotTooBig =
228                                    new Point2D.Double(nextXnotTooBig, nextYnotTooBig);
229    
230                            Point2D correctedNextPosition =
231                                    a.closestPointTo(
232                                            nextPosNotTooBig,
233                                            a.getRadius()
234                                                    - me.getRadiusBody()
235                                                    - CLOSEST_DISTANCE_TO_WALL);
236    //                      g.setColor(Color.GREEN);
237    //                      g.fillOval(
238    //                              (int) correctedNextPosition.getX() - 2,
239    //                              (int) correctedNextPosition.getY() - 2,
240    //                              4,
241    //                              4);
242                            r.add(movVector);
243                            Vector2D toRemove =
244                                    new Vector2D(nextPosition, correctedNextPosition);
245                            r.add(toRemove);
246    //                      r.paint(me.getCoord(), g, Color.GREEN);
247    
248    //                      try {
249    //                              Thread.sleep(5000);
250    //                      } catch (InterruptedException e) {
251    //                      }
252    
253                    }
254    
255                    return r;
256            }
257    
258    }