Created
June 25, 2011 23:11
-
-
Save Clancey/1047006 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using MonoTouch.UIKit; | |
using System.Collections.Generic; | |
using MonoTouch.MapKit; | |
using System.Threading; | |
using ClanceysLib; | |
using MonoTouch.Foundation; | |
using System.Linq; | |
using MonoTouch.CoreLocation; | |
using System.Drawing; | |
using MapStuff.DrawMap; | |
using MonoTouch.ObjCRuntime; | |
using System.Xml.Linq; | |
using MonoTouch.CoreGraphics; | |
namespace ParkApp | |
{ | |
public class MapViewController : UIViewController | |
{ | |
public List<MKPolyline> roads = new List<MKPolyline> (); | |
public Park Park; | |
public MKMapView map; | |
public UISegmentedControl switcher; | |
public MBProgressHUD progress; | |
public MKMapRect maxRect; | |
public List<PersonAnnotation> People; | |
public bool LockMap = false; | |
public PartySettingsDvc partySettingsDvc; | |
public MapViewController (Park park) : base() | |
{ | |
People = new List<PersonAnnotation> (); | |
Park = park; | |
map = new MKMapView (); | |
map.Frame = this.View.Bounds; | |
map.MapType = MKMapType.Hybrid; | |
map.Region = getMapBounds (); | |
//map.SetVisibleMapRect(new MKMapRect(46286327.3006886 , 107394439.844582,12713.8773526251 , 8475.9182350859),false); | |
maxRect = map.visibleMapRect; | |
map.Delegate = new MapViewDelegate (this); | |
map.ShowsUserLocation = true; | |
switcher = new UISegmentedControl (new string[] { "Rides", "Food", "Restrooms" }); | |
switcher.Frame = new RectangleF (35, 0, 250, 25); | |
switcher.ControlStyle = UISegmentedControlStyle.Bar; | |
switcher.SelectedSegment = 0; | |
switcher.ValueChanged += delegate { ShowAnnotations (); }; | |
this.NavigationItem.RightBarButtonItem = new UIBarButtonItem ("Party", UIBarButtonItemStyle.Plain, delegate { | |
partySettingsDvc = new PartySettingsDvc(); | |
this.NavigationController.PushViewController(partySettingsDvc,true); | |
}); | |
this.NavigationItem.TitleView = switcher; | |
this.View.AddSubview (map); | |
progress = new MBProgressHUD (UIApplication.SharedApplication.KeyWindow); | |
Thread thread = new Thread (LoadPaths); | |
thread.Start (); | |
//AddPaths(); | |
//AddWays(); | |
//this.Add(new OptionsView()); | |
} | |
public override void ViewDidAppear (bool animated) | |
{ | |
//this.NavigationItem.TitleView.AddSubview(switcher); | |
base.ViewDidAppear (animated); | |
} | |
public override void ViewWillAppear (bool animated) | |
{ | |
base.ViewWillAppear (animated); | |
} | |
public void UpdatePeopleLocations (ParkHopperLibrary.Models.PartyMember[] people) | |
{ | |
map.RemoveAnnotations (People.ToArray ()); | |
People.Clear (); | |
foreach (var person in people) | |
{ | |
var ann = new PersonAnnotation (person); | |
People.Add (ann); | |
map.AddAnnotation (ann); | |
} | |
} | |
public MKCoordinateRegion getMapBounds () | |
{ | |
return new MKCoordinateRegion (new CLLocationCoordinate2D (33.8092652025279, -117.919469247912), new MKCoordinateSpan (0.0135665781450101, 0.0113583849480818)); | |
} | |
bool hasAnnotations; | |
public void ShowAnnotations () | |
{ | |
Console.WriteLine ("start"); | |
if (hasAnnotations) | |
{ | |
map.RemoveAnnotations (map.Annotations.Where (x => x is MyAnnotation || x is RestaurantAnnotation || x is RestroomAnnotation).Select (x => (MKAnnotation)x).ToArray ()); | |
hasAnnotations = false; | |
} | |
Console.WriteLine ("past the linq"); | |
Thread thread = new Thread (getAnnotations); | |
thread.Start (); | |
} | |
private void getAnnotations () | |
{ | |
using (new NSAutoreleasePool ()) | |
{ | |
if (switcher.SelectedSegment == 0) | |
AddAttactions (); | |
else if (switcher.SelectedSegment == 1) | |
AddFood(); | |
else | |
{ | |
AddRestrooms(); | |
} | |
} | |
} | |
private void AddFood() | |
{ | |
Console.WriteLine("Add Restaurants"); | |
var restaurants = Database.Main.Table<Restaurant>().Where(x=> x.Park == Park).ToArray(); | |
foreach( var restaurant in restaurants) | |
{ | |
this.InvokeOnMainThread( delegate { | |
map.AddAnnotation(new RestaurantAnnotation(restaurant)); | |
}); | |
hasAnnotations = true; | |
} | |
} | |
private void AddRestrooms() | |
{ | |
Console.WriteLine("Add Restrooms"); | |
var restroooms = Database.Main.Table<Restroom>().Where(x=> x.Park == Park).ToArray(); | |
foreach( var restroom in restroooms) | |
{ | |
this.InvokeOnMainThread( delegate { | |
map.AddAnnotation(new RestroomAnnotation(restroom)); | |
}); | |
hasAnnotations = true; | |
} | |
} | |
public void AddAttactions () | |
{ | |
Console.WriteLine ("Add Attractions"); | |
var attractions = Database.Main.Table<Tag> ().Where (x => x.k == "attraction" && x.Park == Park).Select (y => y.nodeId).ToArray (); | |
foreach (var attraction in attractions) | |
{ | |
var name = Database.Main.Table<Tag> ().Where (x => x.nodeId == attraction && x.k == "name").Select (y => y.v).FirstOrDefault () ?? ""; | |
var type = Database.Main.Table<Tag> ().Where (x => x.nodeId == attraction && x.k == "attraction").Select (y => y.v).FirstOrDefault () ?? ""; | |
var node = Database.Main.Table<Node> ().Where (x => x.id == attraction).FirstOrDefault (); | |
this.BeginInvokeOnMainThread (delegate { map.AddAnnotation (new MyAnnotation (new CLLocationCoordinate2D (node.lat, node.lon), name, type, node.id)); }); | |
hasAnnotations = true; | |
} | |
} | |
public void LoadPaths () | |
{ | |
using (new NSAutoreleasePool ()) | |
{ | |
progress.Show (true); | |
//AddWays(); | |
addWaysDatabase (); | |
ShowAnnotations (); | |
progress.Hide (true); | |
} | |
} | |
public void addWaysDatabase () | |
{ | |
var ways = Database.Main.Table<Way> ().ToArray (); | |
foreach (var way in ways) | |
{ | |
List<CLLocationCoordinate2D> points = new List<CLLocationCoordinate2D> (); | |
foreach (var node in Database.Main.Table<WayNode> ().Where (x => x.WayId == way.id).ToArray ()) | |
{ | |
points.Add (new CLLocationCoordinate2D (node.lat, node.lon)); | |
} | |
map.AddOverlay (MKPolyline.FromCoordinates (points.ToArray ())); | |
} | |
} | |
public class MyAnnotation : MKAnnotation | |
{ | |
private CLLocationCoordinate2D _coordinate; | |
private string _title, _subtitle; | |
public override CLLocationCoordinate2D Coordinate { | |
get { return _coordinate; } | |
set { _coordinate = value; } | |
} | |
public override string Title { | |
get { return _title; } | |
} | |
public override string Subtitle { | |
get { return _subtitle; } | |
} | |
public long NodeId { get; set; } | |
/// <summary> | |
/// Need this constructor to set the fields, since the public | |
/// interface of this class is all READ-ONLY | |
/// <summary> | |
public MyAnnotation (CLLocationCoordinate2D coord, string t, string s, long nodeID) : base() | |
{ | |
_coordinate = coord; | |
_title = t; | |
_subtitle = s; | |
NodeId = nodeID; | |
} | |
} | |
public class PersonAnnotation : MKAnnotation | |
{ | |
public ParkHopperLibrary.Models.PartyMember PartyMember { get; set; } | |
private CLLocationCoordinate2D _coordinate; | |
private string _title, _subtitle; | |
public override CLLocationCoordinate2D Coordinate { | |
get { return _coordinate; } | |
set { _coordinate = value; } | |
} | |
public override string Title { | |
get { return _title; } | |
} | |
public override string Subtitle { | |
get { return _subtitle; } | |
} | |
public long NodeId { get; set; } | |
/// <summary> | |
/// Need this constructor to set the fields, since the public | |
/// interface of this class is all READ-ONLY | |
/// <summary> | |
public PersonAnnotation (ParkHopperLibrary.Models.PartyMember partyMember) : base() | |
{ | |
_coordinate = new CLLocationCoordinate2D (partyMember.Latitude, partyMember.Longitude); | |
_title = partyMember.DisplayName; | |
_subtitle = (DateTime.UtcNow - partyMember.LastUpdate).ToString (); | |
PartyMember = partyMember; | |
} | |
public UIFont Font { | |
get { return UIFont.FromName ("Helvetica", 12);} | |
} | |
public void UpdatesPerson (ParkHopperLibrary.Models.PartyMember partyMember) | |
{ | |
PartyMember = partyMember; | |
_coordinate = new CLLocationCoordinate2D (partyMember.Latitude, partyMember.Longitude); | |
} | |
UIImage image; | |
public UIImage Image (SizeF textSize) | |
{ | |
if(image == null) | |
using (var cs = CGColorSpace.CreateDeviceRGB ()) | |
{ | |
UIImage template = Images.Person; | |
var height = template.Size.Height + textSize.Height; | |
var width = Math.Max( template.Size.Width , textSize.Width); | |
using (var context = new CGBitmapContext (IntPtr.Zero,(int) width,(int) height, template.CGImage.BitsPerComponent, 0, cs, CGImageAlphaInfo.PremultipliedLast)) | |
{ | |
//context.ScaleCTM (0.5f, -1); | |
//context.TranslateCTM (0, 0); | |
context.TranslateCTM (0, 0); | |
context.DrawImage (new RectangleF ((width - template.Size.Width) / 2,0, template.Size.Width, template.Size.Height), template.CGImage); | |
context.SetRGBFillColor (1, 1, 1, 1); | |
context.SelectFont ("Helvetica", 12f, CGTextEncoding.MacRoman); | |
// Pretty lame way of measuring strings, as documented: | |
var ns = new NSString (PartyMember.DisplayName); | |
UIFont ff = UIFont.FromName ("Helvetica", 10); | |
//context.ScaleCTM (-1, 1); | |
float textX = (width - textSize.Width) / 2; | |
float textY = height - textSize.Height; | |
context.SetTextDrawingMode (CGTextDrawingMode.Fill); | |
context.ShowTextAtPoint (textX,textY, PartyMember.DisplayName); | |
// The big string | |
context.SetRGBFillColor (0, 0, 0, 1); | |
context.SetTextDrawingMode (CGTextDrawingMode.Fill); | |
context.StrokePath (); | |
image = UIImage.FromImage (context.ToImage ()); | |
} | |
} | |
return image; | |
} | |
} | |
public class RestaurantAnnotation : MKAnnotation | |
{ | |
public Restaurant Restaurant { get; set; } | |
private CLLocationCoordinate2D _coordinate; | |
private string _title, _subtitle; | |
public override CLLocationCoordinate2D Coordinate { | |
get { return _coordinate; } | |
set { _coordinate = value; } | |
} | |
public override string Title { | |
get { return _title; } | |
} | |
public override string Subtitle { | |
get { return _subtitle; } | |
} | |
public long NodeId { get; set; } | |
/// <summary> | |
/// Need this constructor to set the fields, since the public | |
/// interface of this class is all READ-ONLY | |
/// <summary> | |
public RestaurantAnnotation (Restaurant restaurant) : base() | |
{ | |
_coordinate = new CLLocationCoordinate2D (restaurant.lat, restaurant.lon); | |
_title = restaurant.Name; | |
_subtitle = restaurant.Cuisine ; | |
Restaurant = restaurant; | |
} | |
} | |
public class RestroomAnnotation : MKAnnotation | |
{ | |
public Restroom Restroom { get; set; } | |
private CLLocationCoordinate2D _coordinate; | |
private string _title, _subtitle; | |
public override CLLocationCoordinate2D Coordinate { | |
get { return _coordinate; } | |
set { _coordinate = value; } | |
} | |
public override string Title { | |
get { return _title; } | |
} | |
public override string Subtitle { | |
get { return _subtitle; } | |
} | |
public long NodeId { get; set; } | |
/// <summary> | |
/// Need this constructor to set the fields, since the public | |
/// interface of this class is all READ-ONLY | |
/// <summary> | |
public RestroomAnnotation (Restroom restroom) : base() | |
{ | |
_coordinate = new CLLocationCoordinate2D (restroom.lat, restroom.lon); | |
Restroom = restroom; | |
} | |
} | |
class MapViewDelegate : MKMapViewDelegate | |
{ | |
MapViewController _viewController; | |
MKMapRect lastGoodMapRect; | |
bool manuallyChangingMapRect; | |
public MapViewDelegate (MapViewController viewController) | |
{ | |
_viewController = viewController; | |
} | |
public override void RegionWillChange (MKMapView mapView, bool animated) | |
{ | |
if (manuallyChangingMapRect) | |
return; | |
lastGoodMapRect = mapView.visibleMapRect; | |
} | |
/* | |
if (_viewController.currentAnnotationView != null) | |
{ | |
_viewController.currentAnnotationView.Hidden = true; | |
} | |
*/ | |
public bool MKMapRectContainsRect (MKMapRect firstRect, MKMapRect secondRect) | |
{ | |
var rect2 = (new Rectangle ((int)secondRect.MinX, (int)secondRect.MinY, (int)(secondRect.MaxX - secondRect.MinX), (int)(secondRect.MaxY - secondRect.MinY))); | |
return (new Rectangle ((int)firstRect.MinX, (int)firstRect.MinY, (int)(firstRect.MaxX - firstRect.MinX), (int)(firstRect.MaxY - firstRect.MinY))).Contains (rect2); | |
} | |
public override void RegionChanged (MKMapView mapView, bool animated) | |
{ | |
if (manuallyChangingMapRect || !_viewController.LockMap) | |
//prevents possible infinite recursion when we call setVisibleMapRect below | |
return; | |
bool mapContainsOverlay = MKMapRectContainsRect (mapView.visibleMapRect, _viewController.maxRect); | |
if (mapContainsOverlay) | |
{ | |
// The overlay is entirely inside the map view but adjust if user is zoomed out too much... | |
double widthRatio = _viewController.maxRect.Size.Width / mapView.visibleMapRect.Size.Width; | |
double heightRatio = _viewController.maxRect.Size.Height / mapView.visibleMapRect.Size.Height; | |
//adjust ratios as needed | |
if ((widthRatio < 0.6) || (heightRatio < 0.6)) | |
{ | |
manuallyChangingMapRect = true; | |
mapView.SetVisibleMapRect (_viewController.maxRect, true); | |
manuallyChangingMapRect = false; | |
} | |
} | |
else if (!_viewController.maxRect.Intersects (mapView.visibleMapRect)) | |
{ | |
// Overlay is no longer visible in the map view. | |
// Reset to last "good" map rect... | |
mapView.SetVisibleMapRect (lastGoodMapRect, true); | |
} | |
} | |
public override MKOverlayView GetViewForOverlay (MKMapView mapView, NSObject overlay) | |
{ | |
MKOverlayView overlayView = null; | |
if (overlay is MKPolygon) | |
{ | |
var polygon = (MKPolygon)overlay; | |
var polygonView = new MKPolygonView (polygon); | |
polygonView.FillColor = polygon.Subtitle == "attraction" ? UIColor.Blue : UIColor.Green; | |
polygonView.StrokeColor = UIColor.Gray; | |
polygonView.LineWidth = 3; | |
overlayView = polygonView; | |
} | |
else if (overlay is MKPolyline) | |
{ | |
var polylineView = new MKPolylineView ((MKPolyline)overlay); | |
polylineView.FillColor = UIColor.Red; | |
polylineView.StrokeColor = UIColor.Red; | |
polylineView.LineJoin = MonoTouch.CoreGraphics.CGLineJoin.Round; | |
polylineView.LineDashPattern = new NSNumber[] { new NSNumber (1), new NSNumber (1) }; | |
polylineView.LineWidth = 3; | |
overlayView = polylineView; | |
} | |
return overlayView; | |
} | |
public override MKAnnotationView GetViewForAnnotation (MKMapView mapView, NSObject annotation) | |
{ | |
MKAnnotationView annotationView = null; | |
if (annotation is MyAnnotation) | |
{ | |
var pin = annotation as MyAnnotation; | |
var pinView = new MKAnnotationView (pin, "colors"); | |
var section = Updates.AttractionSections.Where (x => x.Key == pin.NodeId).Select (y => y.Value).FirstOrDefault () ?? ""; | |
pinView.RightCalloutAccessoryView = UIButton.FromType (UIButtonType.DetailDisclosure); | |
((UIButton)pinView.RightCalloutAccessoryView).TouchDown += delegate { | |
Console.WriteLine("I was touched!"); | |
};//.AddTarget (this, new Selector ("openSpot:"), UIControlEvent.TouchUpInside); | |
pinView.Enabled = true; | |
pinView.CanShowCallout = true; | |
pinView.CenterOffset = new PointF (8, -13); | |
pinView.CalloutOffset = new PointF (-8, 0); | |
pinView.Image = string.IsNullOrEmpty (section) ? Images.GrayPin : Updates.SectionColors[section]; | |
annotationView = pinView; | |
} | |
else if (annotation is PersonAnnotation) | |
{ | |
var person = annotation as PersonAnnotation; | |
var view = new MKAnnotationView (person, "person"); | |
view.Image = person.Image(view.StringSize(person.PartyMember.DisplayName,person.Font)); | |
//view.SetSelected(true,false); | |
view.Enabled = true; | |
view.CanShowCallout = true; | |
view.RightCalloutAccessoryView = UIButton.FromType (UIButtonType.DetailDisclosure); | |
((UIButton)view.RightCalloutAccessoryView).TouchDown += delegate { | |
Console.WriteLine("I was touched!"); | |
var alert = new UIAlertView("Are you sure?","Do you want to send " + person.PartyMember.DisplayName + " and update request?",null,"No Thanks","Yes"); | |
alert.Dismissed += delegate(object sender, UIButtonEventArgs e) { | |
if(e.ButtonIndex > 0){ | |
Settings.ShowNetwork(); | |
} | |
}; | |
alert.Show(); | |
}; | |
annotationView = view; | |
} | |
else if (annotation is RestaurantAnnotation) | |
{ | |
var resaurant = annotation as RestaurantAnnotation; | |
var view = new MKAnnotationView (resaurant, "resaurant"); | |
view.Image = Images.Restaurant; | |
//view.SetSelected(true,false); | |
view.Enabled = true; | |
view.CanShowCallout = true; | |
annotationView = view; | |
} | |
else if (annotation is RestroomAnnotation) | |
{ | |
var restroom = annotation as RestroomAnnotation; | |
var view = new MKAnnotationView (restroom, "restroom"); | |
view.Image = Images.Restroom; | |
//view.SetSelected(true,false); | |
view.Enabled = true; | |
//view.CanShowCallout = true; | |
annotationView = view; | |
} | |
else if (annotation is GeometryAnnotation || annotation is MergedGeometryAnnotation) | |
{ | |
Console.WriteLine ("it's a line class"); | |
//GeometryAnnotation geometryAnnotation = annotation as GeometryAnnotation; | |
LinePolygonAnnotationView _annotationView = new LinePolygonAnnotationView (new RectangleF (0, 0, mapView.Frame.Size.Width, mapView.Frame.Size.Height)); | |
_annotationView.Annotation = annotation; | |
_annotationView.MapView = mapView; | |
//_viewController.currentAnnotationView = _annotationView; | |
annotationView = _annotationView; | |
} | |
return annotationView; | |
} | |
public override void MapLoaded (MKMapView mapView) | |
{ | |
} | |
} | |
/* | |
foreach(var person in _viewController.People) | |
mapView.SelectAnnotation(person,false); | |
*/ | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment