/// <summary> /// Constructs a new Wall object from scratch /// </summary> /// <param name="nx1">X component of endpoint 1</param> /// <param name="ny1">Y component of endpoint 1</param> /// <param name="nx2">X component of endpoint 2</param> /// <param name="ny2">Y component of endpoint 2</param> /// <param name="vis">Is the wall visible?</param> /// <param name="n">Wall name</param> public Wall(double nx1, double ny1, double nx2, double ny2, bool vis, string n) { Name = n; Colored = false; Point2D p1 = new Point2D(nx1, ny1); Point2D p2 = new Point2D(nx2, ny2); Line = new Line2D(p1, p2); //set center point Location = Line.midpoint(); Dynamic = false; Visible = vis; }
public virtual void update(Environment env, List<Robot> robots,CollisionManager cm) { Point2D location = new Point2D(Owner.Location.X, Owner.Location.Y); SimulatorObject hit; DistanceToClosestObject = cm.raycast(Angle,MaxRange,location,Owner,out hit); Debug.Assert(!Double.IsNaN(DistanceToClosestObject), "NaN in inputs"); }
/// <summary> /// Rotates this point about another point. /// </summary> /// <param name="Angle">Angle of rotation, in radians.</param> /// <param name="point">Second point to be rotated about.</param> public void rotate(double angle, Point2D point) { X-=point.X; Y-=point.Y; double ox = X; double oy = Y; X=Math.Cos(angle)*ox - Math.Sin(angle)*oy; Y=Math.Sin(angle)*ox + Math.Cos(angle)*oy; X+=point.X; Y+=point.Y; }
/// <summary> /// Converts a Point2D coordinate from simulator space to display space /// </summary> public Point2D convertToDisplay(Point2D point) { float ox,oy; convertToDisplay((float)point.X,(float)point.Y,out ox, out oy); return new Point2D((double)ox,(double)oy); }
/// <summary> /// Calculates the Euclidean Distance between a Point2D object and a Point object. /// </summary> public static double euclideanDistance(Point2D p1, Point p2) { return Math.Sqrt(Math.Pow(p1.X - p2.X, 2) + Math.Pow(p1.Y - p2.Y, 2)); }
/// <summary> /// Checks the conic area defined by a radar sensor for detectable objects. /// </summary> /// <returns>Distance to the closest object.</returns> public static double scanCone(Radar radar, List<SimulatorObject> objList) { double distance = radar.MaxRange; double new_distance; double heading=radar.Owner.Heading; Point2D point=new Point2D(radar.Owner.Location.X,radar.Owner.Location.Y); double startAngle = radar.StartAngle + heading; double endAngle = radar.EndAngle + heading; double twoPi = 2 * Math.PI; if (startAngle < 0) { startAngle += twoPi; } else if (startAngle > twoPi) { startAngle -= twoPi; } if (endAngle < 0) { endAngle += twoPi; } else if (endAngle > twoPi) { endAngle -= twoPi; } foreach (SimulatorObject obj in objList) { bool found = false; if (obj == radar.Owner) continue; new_distance = point.distance(obj.Location); double angle = Math.Atan2(obj.Location.Y - point.Y, obj.Location.X - point.X); if (angle < 0) { angle += Utilities.twoPi; } if (endAngle < startAngle) { if ((angle >= startAngle && angle <= Math.PI * 2) || (angle >= 0 && angle <= endAngle)) { found = true; } } else if ((angle >= startAngle && angle <= endAngle)) found = true; if (found) { if (new_distance < distance) { distance = new_distance; } } } return distance; }
public abstract double raycast(double angle, double maxRange, Point2D point, Robot owner, out SimulatorObject hit, bool absolute = false);
/// <summary> /// Calculates the point of intersection between two line segments /// </summary> /// <param name="L">Second line segment that is supposed to intersect with this line segment.</param> /// <param name="found">**Output parameter**, will return false if no intersection exists.</param> public Point2D intersection(Line2D line,out bool found) { Point2D pt = new Point2D(0.0,0.0); Point2D A = Endpoint1; Point2D B = Endpoint2; Point2D C = line.Endpoint1; Point2D D = line.Endpoint2; double rTop = (A.Y-C.Y)*(D.X-C.X)-(A.X-C.X)*(D.Y-C.Y); double rBot = (B.X-A.X)*(D.Y-C.Y)-(B.Y-A.Y)*(D.X-C.X); double sTop = (A.Y-C.Y)*(B.X-A.X)-(A.X-C.X)*(B.Y-A.Y); double sBot = (B.X-A.X)*(D.Y-C.Y)-(B.Y-A.Y)*(D.X-C.X); if ((rBot == 0 || sBot == 0)) { found = false; return pt; } double r = rTop/rBot; double s = sTop/sBot; if( (r>0) && (r<1) && (s>0) && (s<1)) { pt.X = A.X + r * (B.X-A.X); pt.Y = A.Y + r * (B.Y - A.Y); found=true; return pt; } else { found = false; return pt; } }
/// <summary> /// Creates a new Line2D object by copying another Line2D. /// </summary> public Line2D(Line2D otherLine2D) { Endpoint1=otherLine2D.Endpoint1; Endpoint2=otherLine2D.Endpoint2; }
/// <summary> /// Creates a new Circle2D object by copying another AreaOfImpact. /// </summary> public Circle2D(Circle2D otherCircle2D) { Position=otherCircle2D.Position; Radius=otherCircle2D.Radius; }
/// <summary> /// Creates a new Line2D object from the specified parameters. /// </summary> public Line2D(Point2D endpoint1, Point2D endpoint2) { Endpoint1=endpoint1; Endpoint2=endpoint2; }
/// <summary> /// Calculates the Manhattan Distance (according to a Cartesian grid coordinate system) to a second point. /// </summary> public double manhattanDistance(Point2D point) { double dx=Math.Abs(point.X-X); double dy=Math.Abs(point.Y-Y); return dx+dy; }
/// <summary> /// Calculates the squared Distance to another point. /// </summary> public double squaredDistance(Point2D point) { double dx=point.X-X; double dy=point.Y-Y; return dx*dx+dy*dy; }
/// <summary> /// Updates the sensor based on the current state of the environment. /// </summary> public void update(Environment env, List<Robot> robots, CollisionManager cm) { Activation = 0; Point2D temp; double dist; double angle; if (Type == "poi") { foreach (Point p in env.POIPosition) { temp = new Point2D(p.X, p.Y); dist = EngineUtilities.euclideanDistance(temp, new Point2D(Owner.AreaOfImpact.Position.X, Owner.AreaOfImpact.Position.Y)); temp.X -= (float)Owner.AreaOfImpact.Position.X; temp.Y -= (float)Owner.AreaOfImpact.Position.Y; angle = (float)temp.angle(); angle -= Owner.Heading; angle *= 57.297f; while (angle > 360) angle -= 360; while (angle < 0) angle += 360; if (StartAngle < 0 && EndAngle > 0) // sensor spans the 0 line { if ((angle >= StartAngle + 360.0 && angle <= 360) || (angle >= 0 && angle <= EndAngle)) { Activation = Math.Max(1.0 - (dist > MaxRange ? 1.0 : dist / MaxRange), Activation); } } else { if (angle >= StartAngle && angle < EndAngle) { Activation = Math.Max(1.0 - (dist > MaxRange ? 1.0 : dist / MaxRange), Activation); } else if (angle + 360.0 >= StartAngle && angle + 360.0 < EndAngle) { Activation = Math.Max(1.0 - (dist > MaxRange ? 1.0 : dist / MaxRange), Activation); } } } return; } if (Type == "goal") temp = new Point2D(env.goal_point.X, env.goal_point.Y); else temp = new Point2D(env.start_point.X, env.start_point.Y); dist = EngineUtilities.euclideanDistance(temp, new Point2D(Owner.AreaOfImpact.Position.X, Owner.AreaOfImpact.Position.Y)); //translate with respect to location of navigator temp.X -= (float)Owner.AreaOfImpact.Position.X; temp.Y -= (float)Owner.AreaOfImpact.Position.Y; angle = (float)temp.angle(); angle *= 57.297f; angle -= (float)Owner.Heading * 57.297f; while (angle > 360) angle -= 360; while (angle < 0) angle += 360; if (angle >= StartAngle && angle < EndAngle) { if (Type == "goal") Activation = 1.0 - (dist > MaxRange ? 1.0 : dist / MaxRange); else Activation = 1.0; } else if (angle + 360.0 >= StartAngle && angle + 360.0 < EndAngle) { if (Type == "goal") Activation = 1.0 - (dist > MaxRange ? 1.0 : dist / MaxRange); else Activation = 1.0; } }
/// <summary> /// Calculate the squared Distance from this line to a point. /// </summary> public double squaredDistance(Point2D point) { double utop = (point.X-Endpoint1.X)*(Endpoint2.X-Endpoint1.X)+(point.Y-Endpoint1.Y)*(Endpoint2.Y-Endpoint1.Y); double ubot = Endpoint1.squaredDistance(Endpoint2); double u = utop/ubot; if(u<0 || u> 1) { double d1 = Endpoint1.squaredDistance(point); double d2 = Endpoint2.squaredDistance(point); if(d1<d2) return d1; return d2; } Point2D p=new Point2D(0.0,0.0); p.X=Endpoint1.X+u*(Endpoint2.X-Endpoint1.X); p.Y=Endpoint1.Y+u*(Endpoint2.Y-Endpoint1.Y); return p.squaredDistance(point); }
/// <summary> /// Initialize the robot. /// </summary> public void init(int id, double locationX, double locationY, double heading, AgentBrain agentBrain, Environment environment, float sensorNoise, float effectorNoise, float headingNoise, float timeStep) { this.ID = id; Radius = defaultRobotSize(); Location = new Point2D(locationX, locationY); AreaOfImpact = new Circle2D(Location, Radius); OldLocation = new Point2D(Location); Heading = heading; Velocity = 0.0; HasCollided = false; this.Timestep = timeStep; this.CurrentEnvironment = environment; this.Brain = agentBrain; this.SensorNoise = sensorNoise; this.EffectorNoise = effectorNoise; this.HeadingNoise = headingNoise; populateSensors(); if (environment.seed != -1) rng = environment.rng; else rng = environment.rng; this.Trajectory = new List<int>(); }
/// <summary> /// Creates a new Circle2D object from the speficied parameters. /// </summary> public Circle2D(Point2D position, double radius) { Radius=radius; Position=position; }
private void MouseMoveHandler(object sender, MouseEventArgs e) { if (drawMode == drawModes.selectMode) { if (bDragDisplay) { //how far has the wall been dragged? int dx = e.X - x1; int dy = e.Y - y1; x1 = e.X; y1 = e.Y; float odx,ody; frame.convertFromDisplayOffset((float)dx,(float)dy,out odx, out ody); frame.X-=odx; frame.Y-=ody; } if (bSelected_wall) { //wall-dragging code //how far has the wall been dragged? int dx = e.X - x1; int dy = e.Y - y1; x1 = e.X; y1 = e.Y; float odx,ody; frame.convertFromDisplayOffset((float)dx,(float)dy,out odx, out ody); if (selectMode == selectModes.dragMode) { //update wall's position selected_wall.Line.Endpoint1.X += odx; selected_wall.Line.Endpoint1.Y += ody; selected_wall.Line.Endpoint2.X += odx; selected_wall.Line.Endpoint2.Y += ody; } if (selectMode == selectModes.rotateMode) { Point2D midpoint = selected_wall.Line.midpoint(); selected_wall.Line.Endpoint1.rotate(dy / 180.0 * 3.14, midpoint); selected_wall.Line.Endpoint2.rotate(dy / 180.0 * 3.14, midpoint); } if (selectMode == selectModes.scaleMode) { selected_wall.Line.scale(1.0 + 0.05 * dy); } Invalidate(); } if (bSelected_robot) { //robot-dragging code //how far has the robot been dragged? int dx = e.X - x1; int dy = e.Y - y1; x1 = e.X; y1 = e.Y; float odx,ody; frame.convertFromDisplayOffset((float)dx,(float)dy,out odx, out ody); //update robot's position if (selectMode == selectModes.dragMode) { selected_robot.Location.X += odx; selected_robot.Location.Y += ody; } if (selectMode == selectModes.rotateMode) { selected_robot.Heading += (dy / 10.0); } if (selectMode == selectModes.scaleMode) { selected_robot.Radius += (dy / 2.0); if (selected_robot.Radius < 1.0) selected_robot.Radius = 1.0; selected_robot.AreaOfImpact.Radius = selected_robot.Radius; } Invalidate(); } } if (drawMode == drawModes.selectMode && !bSelected_wall && !bSelected_robot) { selected_wall = null; selected_robot = null; display_snap = false; //find snap Point2D newpoint = new Point2D((double)e.X, (double)e.Y); if (experiment != null) { if(experiment.robots!=null) foreach (Robot robot in experiment.robots) { Point2D screen_location = frame.convertToDisplay(robot.Location); if (screen_location.distance(newpoint) < 20.0) { display_snap = true; snapx = (int)screen_location.X; snapy = (int)screen_location.Y; selected_robot = robot; } } if(experiment.environment.walls!=null) foreach (Wall wall in experiment.environment.walls) { Point2D screen_location = frame.convertToDisplay(wall.Location); if (screen_location.distance(newpoint) < 20.0) { display_snap = true; snapx = (int)screen_location.X; snapy = (int)screen_location.Y; selected_wall = wall; } } int index = 0; if (experiment.environment.walls != null) foreach (Point p in experiment.environment.POIPosition) { Point2D screen_location = frame.convertToDisplay(new Point2D(p.X, p.Y)); if (screen_location.distance(newpoint) < 20.0) { display_snap = true; snapx = (int)screen_location.X; snapy = (int)screen_location.Y; selected_POI = index; } index++; } } Invalidate(); } if (drawMode == drawModes.wallMode) { display_snap = false; //find snap Point2D newpoint = new Point2D((double)e.X, (double)e.Y); foreach (Wall wall in experiment.environment.walls) { Point2D screen_location1 = frame.convertToDisplay(wall.Line.Endpoint1); Point2D screen_location2 = frame.convertToDisplay(wall.Line.Endpoint2); if (screen_location1.distance(newpoint) < 10.0) { display_snap = true; snapx = (int)screen_location1.X; snapy = (int)screen_location1.Y; } if (screen_location2.distance(newpoint) < 10.0) { display_snap = true; snapx = (int)screen_location2.X; snapy = (int)screen_location2.Y; } } x2 = e.X; y2 = e.Y; Invalidate(); } if (drawMode == drawModes.AOIMode && displayAOIRectangle) { float ox,oy; frame.convertFromDisplay(e.X,e.Y,out ox,out oy); experiment.environment.AOIRectangle = new Rectangle(experiment.environment.AOIRectangle.X, experiment.environment.AOIRectangle.Y,(int) ox - experiment.environment.AOIRectangle.X, (int) oy - experiment.environment.AOIRectangle.Y); Invalidate(); } }
/// <summary> /// Calculate the Distance from this line to a point /// </summary> public double distance(Point2D point) { return Math.Sqrt(squaredDistance(point)); }
public static bool collide(Wall wall, Robot robot) { Point2D a1 = new Point2D(wall.Line.Endpoint1); Point2D a2 = new Point2D(wall.Line.Endpoint2); Point2D b = new Point2D(robot.Location.X, robot.Location.Y); if (!wall.Visible) return false; double rad = robot.Radius; double r = ((b.X - a1.X) * (a2.X - a1.X) + (b.Y - a1.Y) * (a2.Y - a1.Y)) / wall.Line.squaredLength(); double px = a1.X + r * (a2.X - a1.X); double py = a1.Y + r * (a2.Y - a1.Y); Point2D np = new Point2D(px, py); double rad_sq = rad * rad; if (r >= 0.0f && r <= 1.0f) { if (np.squaredDistance(b) < rad_sq) return true; else return false; } double d1 = b.squaredDistance(a1); double d2 = b.squaredDistance(a2); if (d1 < rad_sq || d2 < rad_sq) return true; else return false; }
/// <summary> /// Creates a new Point2D object by copying another Point2D /// </summary> /// <param name="otherPoint2D"></param> public Point2D(Point2D otherPoint2D) { X=otherPoint2D.X; Y=otherPoint2D.Y; }
/// <summary> /// Calculates the squared Distance between two Point2D objects. /// </summary> public static double squaredDistance(Point2D p1, Point2D p2) { return Math.Pow(p1.X - p2.X, 2) + Math.Pow(p1.Y - p2.Y, 2); }
/// <summary> /// Casts a ray from the robot's center point according to the specified Angle and returns the Distance to the closest object. /// </summary> /// <param name="Angle">Angle of sensor, in radians. Also see the "absolute" parameter.</param> /// <param name="maxRange">Max Distance that the robot can see in front of itself.</param> /// <param name="point">2D location of the robot's center.</param> /// <param name="Owner">The currently active robot.</param> /// <param name="hit">** Output variable ** - true if another object intersects the cast ray, false otherwise.</param> /// <param name="absolute">If false, the Angle parameter is relative to the agent's Heading. Otherwise it follows the standard unit AreaOfImpact.</param> /// <returns></returns> public override double raycast (double angle, double maxRange, Point2D point, Robot owner, out SimulatorObject hit, bool absolute = false) { hit=null; Point2D casted = new Point2D(point); double distance = maxRange; // Cast point casted out from the robot's center point along the sensor direction if (!absolute) { casted.X += Math.Cos(angle + owner.Heading) * distance; casted.Y += Math.Sin(angle + owner.Heading) * distance; } else { casted.X += Math.Cos(angle) * distance; casted.Y += Math.Sin(angle) * distance; } // Create line segment from robot's center to casted point Line2D cast = new Line2D(point, casted); // Now do naive detection of collision of casted rays with objects // First for all walls foreach (Wall wall in Domain.walls) { if (!wall.Visible) continue; bool found = false; Point2D intersection = wall.Line.intersection(cast, out found); if (found) { double new_distance = intersection.distance(point); if (new_distance < distance) { distance = new_distance; hit=wall; } } } // Then for all robots if(!AgentVisible) return distance; foreach (Robot robot2 in Robots) { bool found = false; if (robot2 == owner) continue; double new_distance = cast.nearestIntersection(robot2.AreaOfImpact, out found); if (found) { if (new_distance < distance) { distance = new_distance; hit=robot2; } } } return distance; }
/// <summary> /// Calculates the Euclidean Distance between a Point object and a Point2D object. /// </summary> public static double euclideanDistance(Point p1, Point2D p2) { return euclideanDistance(p2, p1); }
/// <summary> /// Called on every simulation tick. If this is the first tick, initialize some instance variables. On every other tick, check to see if the robot is within stopping Distance of the goal. /// </summary> void IFitnessFunction.update(SimulatorExperiment Experiment, Environment environment, instance_pack ip) { // Initialization routines if (first) { first = false; if (DEBUG) { // If debugging: Add POI at thirds along the border of the AOI rectangle, so we can arrange the maze properly // This functionality helps align the maze with the MAP-Elites grid. environment.POIPosition.Clear(); if (!DEBUG_CLEARONLY) { double dwidth = environment.AOIRectangle.Width / NumBinsPerDim; double dheight = environment.AOIRectangle.Height / NumBinsPerDim; double cornerx = environment.AOIRectangle.Left; double cornery = environment.AOIRectangle.Top; for (int x = 0; x <= NumBinsPerDim; x++) { for (int y = 0; y <= NumBinsPerDim; y++) { environment.POIPosition.Add(new Point((int)(cornerx + dwidth * x), (int)(cornery + dheight * y))); } } } } // Compute the max possible Distance a robot can achieve from the goal point while staying in the AOI bounds double maxSoFar = 0; // Top left Point2D cornerWeCareAboutRightNow = new Point2D(environment.AOIRectangle.Left, environment.AOIRectangle.Top); double tempDist = environment.goal_point.distance(cornerWeCareAboutRightNow); if (tempDist > maxSoFar) maxSoFar = tempDist; // Top right cornerWeCareAboutRightNow = new Point2D(environment.AOIRectangle.Right, environment.AOIRectangle.Top); tempDist = environment.goal_point.distance(cornerWeCareAboutRightNow); if (tempDist > maxSoFar) maxSoFar = tempDist; // Bottom right cornerWeCareAboutRightNow = new Point2D(environment.AOIRectangle.Right, environment.AOIRectangle.Bottom); tempDist = environment.goal_point.distance(cornerWeCareAboutRightNow); if (tempDist > maxSoFar) maxSoFar = tempDist; // Bottom left cornerWeCareAboutRightNow = new Point2D(environment.AOIRectangle.Left, environment.AOIRectangle.Bottom); tempDist = environment.goal_point.distance(cornerWeCareAboutRightNow); if (tempDist > maxSoFar) maxSoFar = tempDist; // Define the Distance (that will be used to calculate fitness values) (add a small value (10) to give a little breathing room) MaxDistanceToGoal = maxSoFar + 10; } if (ip.robots[0].Location.squaredDistance(environment.goal_point) < StoppingRange) { ip.robots[0].Stopped = true; } return; }
/// <summary> /// Updates all of the robot's GoalSensors. Called on each simulator tick. /// </summary> /// <param name="env">The simulator CurrentEnvironment.</param> /// <param name="robots">List of other robots in the CurrentEnvironment. Not actually used in this function, only included for inheritance reasons.</param> /// <param name="cm">The CurrentEnvironment's collision manager.</param> public override void updateSensors(Environment env, List<Robot> robots, CollisionManager cm) { // Clear out GoalSensors from last time InputValues.Clear(); foreach (Radar r in GoalSensors) { r.Activation = 0; } foreach (Radar r in CompassSensors) { r.Activation = 0; } // Update regular (target) GoalSensors double angle = 0; Point2D temp; temp = new Point2D(env.goal_point.X, env.goal_point.Y); temp.X -= (float)AreaOfImpact.Position.X; temp.Y -= (float)AreaOfImpact.Position.Y; angle = (float)temp.angle(); angle -= Heading; angle *= 57.297f; // convert radians to degrees while (angle > 360) angle -= 360; while (angle < 0) angle += 360; foreach (Radar r in GoalSensors) { // First, check if the Angle is in the wonky pie slice if ((angle < 45 || angle >= 315) && r.StartAngle == 315) { r.Activation = 1; break; } // Then check the other pie slices else if (angle >= r.StartAngle && angle < r.EndAngle) { r.Activation = 1; break; } } // Update the compass/northstar GoalSensors // Note: This is trivial compared to rangefinder updates, which check against all walls for collision. No need to gate it to save CPU. double northstarangle = Heading; northstarangle *= 57.297f; // convert radians to degrees while (northstarangle > 360) northstarangle -= 360; while (northstarangle < 0) northstarangle += 360; foreach (Radar r in CompassSensors) { // First, check if the Angle is in the wonky pie slice if ((northstarangle < 45 || northstarangle >= 315) && r.StartAngle == 315) { r.Activation = 1; break; } // Then check the other pie slices else if (northstarangle >= r.StartAngle && northstarangle < r.EndAngle) { r.Activation = 1; break; } } // Update the rangefinders foreach (RangeFinder r in WallSensors) { r.update(env, robots, cm); } // Update wall sensor inputs for (int j = 0; j < WallSensors.Count; j++) { Inputs[j] = (float)(1 - (WallSensors[j].getActivation())); if (Inputs[j] > 1.0) Inputs[j] = 1.0f; } // Update pie slice sensor inputs for (int j = WallSensors.Count; j < WallSensors.Count + GoalSensors.Count; j++) { Inputs[j] = (float)GoalSensors[j-WallSensors.Count].getActivation(); if (Inputs[j] > 1.0) Inputs[j] = 1.0f; } // Update NN inputs based on GoalSensors Brain.setInputSignals(ID, Inputs); // Make the sensor values accessible to the behavior characterization for (int i = 0; i < Inputs.Length; i++) InputValues.Add(Inputs[i]); }
/// <summary> /// Resets the CurrentEnvironment to a small, blank square. /// </summary> public void reset() { seed = 0; view_x = 0.0f; view_y = 0.0f; view_scale = 5.0f; AOIRectangle = new Rectangle(30, 60, 640, 500); group_orientation = 0; robot_spacing = 30; robot_heading = 0; rng = new SharpNeatLib.Maths.FastRandom(); walls = new List<Wall>(); POIPosition = new List<Point>(); start_point = new Point2D(0, 0); goal_point = new Point2D(100, 100); }