func makePolyLine(points []sphere.NVector) *gsm.PolyLine { pl := gsm.NewPolyLine() for _, point := range points { lat, lon := point.ToLatLonDegrees() pl.AddPointLatLon(lat, lon) } return pl }
func main() { flag.Parse() // Scan the arguments list in, err := os.Open(*inputFileName) if err != nil { panic("couldn't open input file \"" + *inputFileName + "\"") } defer func() { in.Close() }() for caseNumber := 1; ; caseNumber++ { var airportCount int var maxRadiusKm float64 _, err = fmt.Fscan(in, &airportCount, &maxRadiusKm) if nil != err { break } fmt.Printf("Case %d:\n", caseNumber) airportsByIndex := make([]*g.Node, airportCount+1) airportsByName := make(map[string]*g.Node) airportRadiusNodes := make(map[*g.Node]*[]*g.Node) graph := g.NewGraph() for i := 1; i <= airportCount; i++ { var lat, lon float64 _, err = fmt.Fscan(in, &lon, &lat) if nil != err { panic("couldn't read lon-lat") } var name string names := make([]string, 0) if *readNames { for _, err = fmt.Fscanf(in, "%q", &name); err == nil; _, err = fmt.Fscanf(in, "%q", &name) { names = append(names, name) } } else { name = fmt.Sprintf("Airport %d", i) names = append(names, name) } ap := sphere.NewNVectorFromLatLongDeg(lat, lon) airport := Airport{*ap, names[0]} node := graph.NewNode(&airport) airportsByIndex[i] = node for _, name = range names { airportsByName[name] = node } sl := make([]*g.Node, 0) airportRadiusNodes[node] = &sl } radiusAngleRadians := maxRadiusKm / EARTH_RADIUS_KM circleRadiusKm := math.Sin(radiusAngleRadians) * EARTH_RADIUS_KM circleEarthRadiusKm := math.Cos(radiusAngleRadians) * EARTH_RADIUS_KM if *verbose { fmt.Printf("circle radius = %f; earth circle radius = %f\n", circleRadiusKm, circleEarthRadiusKm) } for airport1Node, midpoints1 := range airportRadiusNodes { airport1 := airport1Node.Record.(*Airport) if DEBUG&CONNECT_AIRPORTS != 0 { fmt.Printf("Connecting %q to other airports.\n", airport1.name) } inner: for airport2Node, midpoints2 := range airportRadiusNodes { airport2 := airport2Node.Record.(*Airport) if !airport1.NVector.LessThan(&airport2.NVector) { continue inner } airportAngle := airport1.NVector.AngleBetween(&airport2.NVector) distance := airportAngle * EARTH_RADIUS_KM if *verbose { fmt.Printf("airports %s and %s are %f km apart consider:%t.\n", airport1.name, airport2.name, distance, distance <= 2*maxRadiusKm) } if distance <= 2*maxRadiusKm { graph.ConnectBi(airport1Node, airport2Node, distance) perp := airport1.NVector.CrossProduct(&airport2.NVector).Normalize() toMeetV1 := perp.CrossProduct(&airport1.NVector) toMeetV2 := airport2.NVector.CrossProduct(perp) discCenter1 := airport1.ScaleTo(circleEarthRadiusKm) discCenter2 := airport2.ScaleTo(circleEarthRadiusKm) discMeetDistance := math.Tan(airportAngle/2) * circleEarthRadiusKm discMeetPoint := discCenter1.Add(toMeetV1.ScaleTo(discMeetDistance)) discMeetPointAlt := discCenter2.Add(toMeetV2.ScaleTo(discMeetDistance)) // REMOVE if *verbose { fmt.Printf("%s and %s -> %s\n", airport1.name, airport2.name, toMeetV1.String()) fmt.Printf(" %s==%s\n", discMeetPoint.String(), discMeetPointAlt.String()) } sphereRadiusFunc := func(in float64) float64 { return perp.ScaleBy(in).Add(discMeetPoint).Magnitude() } intersectionFactor1, ok1 := ipolate.Interpolator(0.0, circleRadiusKm, EARTH_RADIUS_KM, INTERPOLATION_PRECISION, sphereRadiusFunc) intersectionFactor2, ok2 := ipolate.Interpolator(0.0, -circleRadiusKm, EARTH_RADIUS_KM, INTERPOLATION_PRECISION, sphereRadiusFunc) if ok1 && ok2 { airportPair := [2]*Airport{airport1Node.Record.(*Airport), airport2Node.Record.(*Airport)} intersection1 := perp.ScaleBy(intersectionFactor1).Add(discMeetPoint) // REMOVE name1 := fmt.Sprintf("intersection A of %s and %s", airport1.name, airport2.name) location1 := AirportIntersection{*intersection1, airportPair} node1 := graph.NewNode(&location1) intersection2 := perp.ScaleBy(intersectionFactor2).Add(discMeetPoint) // REMOVE name2 := fmt.Sprintf("intersection B of %s and %s", airport1.name, airport2.name) location2 := AirportIntersection{*intersection2, airportPair} node2 := graph.NewNode(&location2) createRoutes(graph, airport1Node, node1, midpoints1, maxRadiusKm) createRoutes(graph, airport1Node, node2, midpoints1, maxRadiusKm) createRoutes(graph, airport2Node, node1, midpoints2, maxRadiusKm) createRoutes(graph, airport2Node, node2, midpoints2, maxRadiusKm) *midpoints1 = append(*midpoints1, node1, node2) *midpoints2 = append(*midpoints2, node1, node2) } else if ok1 || ok2 { panic("only one point found with two nearby airports") } else { panic("no points found with two nearby airports") } } else { if *verbose { fmt.Println("too great") } } } } var flightCount int fmt.Fscan(in, &flightCount) for flight := 0; flight < flightCount; flight++ { var planeRange float64 var airportFrom, airportTo *g.Node if *readNames { var airportFromName, airportToName string _, err = fmt.Fscanf(in, "%q %q %f", &airportFromName, &airportToName, &planeRange) if err != nil { panic("could not read names of airports on route") } airportFrom = airportsByName[airportFromName] airportTo = airportsByName[airportToName] } else { var airportFromIndex, airportToIndex int _, err = fmt.Fscanf(in, "%d %d %f", &airportFromIndex, &airportToIndex, &planeRange) if err != nil { panic("could not read indexes of airports on route") } else { airportFrom = airportsByIndex[airportFromIndex] airportTo = airportsByIndex[airportToIndex] } } if *verbose { fmt.Printf("from %s to %s with max plane range of %f\n", airportFrom.Record.(*Airport).String(), airportTo.Record.(*Airport).String(), planeRange) } fs := newFlightState(planeRange, planeRange) route, distance, ok := graph.Traverse(fs, airportFrom, airportTo) if ok { fmt.Printf("%0.3f\n", distance) if DEBUG&PRINT_ROUTE != 0 { for _, n := range route { fmt.Println(n.Record.String()) } } if *googleMapsURL { gmap := gsm.NewMap(640, 640, 2) airportsSeen := make(map[*Airport]bool) flightPath := make([]sphere.NVector, 0, len(route)) for _, n := range route { if airport, isAirport := n.Record.(*Airport); isAirport { airportsSeen[airport] = true lat, lon := airport.NVector.ToLatLonDegrees() gmap.AddMarker(gsm.NewPoint(lat, lon)) flightPath = append(flightPath, airport.NVector) } else if intersection, isIntersection := n.Record.(*AirportIntersection); isIntersection { airportsSeen[intersection.airports[0]] = true airportsSeen[intersection.airports[1]] = true // lat, lon := intersection.NVector.ToLatLonDegrees() // gmap.AddMarker(gsm.NewPoint(lat, lon)) flightPath = append(flightPath, intersection.NVector) } } for airport, _ := range airportsSeen { pathPoints := airport.NVector.CircleOnSphere(EARTH_RADIUS_KM, maxRadiusKm, 33) polyLine := gsm.NewPolyLine() polyLine.ClosePath = true polyLine.SetWeight(1) polyLine.SetColor("0x0000ffff") polyLine.SetFillColor("0x8080ff40") for _, pp := range pathPoints { lat, lon := pp.ToLatLonDegrees() polyLine.AddPointLatLon(lat, lon) } gmap.AddPath(polyLine) } flightPathPolyLine := makePolyLine(flightPath) flightPathPolyLine.SetWeight(1) flightPathPolyLine.SetColor("0xff0000ff") gmap.AddPath(flightPathPolyLine) fmt.Println(gmap.Encode(true)) } } else { fmt.Println("impossible") } } } }