2012-12-21 23 views
14

चक्र आकर्षित करने के लिए निम्नलिखित कोड होने से (गूगल से लिया Play सेवाओं "मानचित्र" नमूना):एंड्रॉयड मानचित्र API v2 ड्रॉ सर्कल

:

PolylineOptions options = new PolylineOptions(); 
    int radius = 5; //What is that? 
    int numPoints = 100; 
    double phase = 2 * Math.PI/numPoints; 
    for (int i = 0; i <= numPoints; i++) { 
     options.add(new LatLng(SYDNEY.latitude + radius * Math.sin(i * phase), 
       SYDNEY.longitude + radius * Math.cos(i * phase))); 
    } 
    int color = Color.RED; 
    mMap.addPolyline(options 
      .color(color) 
      .width(2)); 

यह वही है दुनिया के विभिन्न हिस्से पर तैयार हो जाता है

Sydney Scandic

जैसा कि आप देख हलकों वास्तव में हलकों और यहां तक ​​कि एक दूसरे के अंडाकार मूल रूप से है नहीं कर रहे हैं।

मुझे लगता है कि int numPoints चर में अंक की संख्या के आधार पर सर्कल का "एंटी-एलियासिंग" है।

  1. int radius = 5 उदाहरण कोड में परिवर्तनीय क्या है? मेरा मतलब है कि यह क्या उपाय है?
  2. और मुख्य प्रश्न मीटर में दिए गए त्रिज्या के साथ अच्छे सर्कल को आकर्षित करने का सही तरीका क्या होगा? कुछ है कि हम क्या साथ canvas.drawCircle()

अद्यतन API v1 में था smiliar --------------------

ठीक गणित में सुधार के बाद मैं करने में सक्षम था आकर्षित "सही" सर्कल:

private void addCircle(LatLng latLng, double radius) 
    { 
     double R = 6371d; // earth's mean radius in km 
     double d = radius/R; //radius given in km 
     double lat1 = Math.toRadians(latLng.latitude); 
     double lon1 = Math.toRadians(latLng.longitude);   
     PolylineOptions options = new PolylineOptions(); 
     for (int x = 0; x <= 360; x++) 
     {      
      double brng = Math.toRadians(x); 
      double latitudeRad = Math.asin(Math.sin(lat1)*Math.cos(d) + Math.cos(lat1)*Math.sin(d)*Math.cos(brng)); 
      double longitudeRad = (lon1 + Math.atan2(Math.sin(brng)*Math.sin(d)*Math.cos(lat1), Math.cos(d)-Math.sin(lat1)*Math.sin(latitudeRad)));    
      options.add(new LatLng(Math.toDegrees(latitudeRad), Math.toDegrees(longitudeRad))); 
     }   
     mMap.addPolyline(options.color(Color.BLACK).width(2));   
    } 

हालांकि चक्र मुझे लगता है की विरोधी aliasing कुछ हद तक नियंत्रण से बाहर है, और पर कुछ ज़ूम स्तर चक्र बदसूरत मिल सकता है:

enter image description here

+3

कारण आप अंडाकार हो रही है क्योंकि यह पर गणित 'options.add (' बहुत ही बुनियादी है और दिखावा पृथ्वी सिर्फ कोपरनिकस पहले की तरह एक सपाट सतह है। आप छोटे क्षेत्रों पर आकर्षित यदि आप एक राउंडर सर्कल प्राप्त होगा। यदि आप एक सटीक सर्कल चाहते हैं तो आप उस गणित को पृथ्वी के आकार को उचित रूप से ध्यान में रखेंगे। – Budius

+0

@ लीजा, ड्रॉ करने के लिए 'पॉलीगॉन' के बजाय 'पॉलीलाइन' का उपयोग करने का कोई विशिष्ट कारण सर्कल? मैंने पॉलीगॉन का उपयोग करने की कोशिश की और मुझे एक ही आउटपुट मिला। तो, आपको कोई विचार है कि उनमें से कौन सा उपयोग करने के लिए सबसे अच्छा है? धन्यवाद। –

+0

@ Archie.bpgc वास्तव में नहीं, आप बहुभुज का उपयोग कर सकते हैं यदि आपको एक उदाहरण के लिए विकल्प भरें। अन्यथा इस मामले में कोई बड़ा अंतर नहीं है। –

उत्तर

20

गूगल मैप्स वी 2 (बिटमैप)

// 1. some variables: 

    private static final double EARTH_RADIUS = 6378100.0; 
    private int offset; 

// 2. convert meters to pixels between 2 points in current zoom: 

    private int convertMetersToPixels(double lat, double lng, double radiusInMeters) { 

     double lat1 = radiusInMeters/EARTH_RADIUS; 
     double lng1 = radiusInMeters/(EARTH_RADIUS * Math.cos((Math.PI * lat/180))); 

     double lat2 = lat + lat1 * 180/Math.PI; 
     double lng2 = lng + lng1 * 180/Math.PI; 

     Point p1 = YourActivity.getMap().getProjection().toScreenLocation(new LatLng(lat, lng)); 
     Point p2 = YourActivity.getMap().getProjection().toScreenLocation(new LatLng(lat2, lng2)); 

     return Math.abs(p1.x - p2.x); 
    } 

// 3. bitmap creation: 

    private Bitmap getBitmap() { 

     // fill color 
     Paint paint1 = new Paint(Paint.ANTI_ALIAS_FLAG); 
     paint1.setColor(0x110000FF); 
     paint1.setStyle(Style.FILL); 

     // stroke color 
     Paint paint2 = new Paint(Paint.ANTI_ALIAS_FLAG); 
     paint2.setColor(0xFF0000FF); 
     paint2.setStyle(Style.STROKE); 

     // icon 
     Bitmap icon = BitmapFactory.decodeResource(YourActivity.getResources(), R.drawable.blue); 

     // circle radius - 200 meters 
     int radius = offset = convertMetersToPixels(lat, lng, 200); 

     // if zoom too small 
     if (radius < icon.getWidth()/2) { 

      radius = icon.getWidth()/2; 
     } 

     // create empty bitmap 
     Bitmap b = Bitmap.createBitmap(radius * 2, radius * 2, Config.ARGB_8888); 
     Canvas c = new Canvas(b); 

     // draw blue area if area > icon size 
     if (radius != icon.getWidth()/2) { 

      c.drawCircle(radius, radius, radius, paint1); 
      c.drawCircle(radius, radius, radius, paint2); 
     } 

     // draw icon 
     c.drawBitmap(icon, radius - icon.getWidth()/2, radius - icon.getHeight()/2, new Paint()); 

     return b; 
    } 

// 4. calculate image offset: 

    private LatLng getCoords(double lat, double lng) { 

     LatLng latLng = new LatLng(lat, lng); 

     Projection proj = YourActivity.getMap().getProjection(); 
     Point p = proj.toScreenLocation(latLng); 
     p.set(p.x, p.y + offset); 

     return proj.fromScreenLocation(p); 
    } 

// 5. draw: 

     MarkerOptions options = new MarkerOptions(); 
      options.position(getCoords(lat, lng)); 
      options.icon(BitmapDescriptorFactory.fromBitmap(getBitmap())); 

      marker = YourActivity.getMap().addMarker(options); 

और परिणाम में चक्र आकर्षित करने के लिए कैसे:

google maps v2 draw circle

+1

आपके समाधान के बावजूद मामूली बग मिला, मुझे एक विचार आया। वी 2 एपीआई के साथ वैसे भी यह छोटे कार्यों की तरह लगता है कि पहले से लागू करना बहुत मुश्किल है। उदाहरण के लिए यदि मुझे प्रगति पट्टी ड्रैग करते समय इस सर्कल का आकार बदलना होगा, तो मुझे मार्कर को हटाना होगा और धीमा होने वाला नया निर्माण करना होगा, मुझे बिटमैप के जीवन चक्र को प्रबंधित करने की आवश्यकता होगी। वी 1 में ओवरले के साथ यह सब बहुत आसान था। –

+0

बस मार्कर मार्कर = map.addMarker (options.position (latLng)) जोड़ने के लिए; यह ठीक काम कर रहा है –

4

यहां मेरा कोड है, बस अतिरिक्त बदलाव के लिए। मैं एंटीलायज़िंग़ या आकार सरलीकरण के साथ समस्याओं को हल करने के लिए एक रास्ता नहीं मिला है:

// Make a circle of latitude and longitude points. 
// Radius is in metres. 
// Probably won't work if the circle is large or near the poles. 
private ArrayList<LatLng> makeCircle(LatLng centre, double radius) 
{ 
    ArrayList<LatLng> points = new ArrayList<LatLng>(); 

    double EARTH_RADIUS = 6378100.0; 
    // Convert to radians. 
    double lat = centre.latitude * Math.PI/180.0; 
    double lon = centre.longitude * Math.PI/180.0; 

    for (double t = 0; t <= Math.PI * 2; t += 0.1) 
    { 
     // y 
     double latPoint = lat + (radius/EARTH_RADIUS) * Math.sin(t); 
     // x 
     double lonPoint = lon + (radius/EARTH_RADIUS) * Math.cos(t)/Math.cos(lat); 
     points.add(new LatLng(latPoint * 180.0/Math.PI, lonPoint * 180.0/Math.PI)); 
    } 

    return points; 
} 

गणित

का स्पष्टीकरण

गूगल अर्थ Mercator projection का उपयोग करता है जिसका अर्थ है कि शारीरिक हलकों नक्शे पर हलकों के रूप में प्रकट नहीं होते हैं - इसके बजाय वे प्रश्न में दिखाए गए विकृत हैं। उन ध्रुवों के करीब जो आप अधिक विकृत हो जाते हैं वे हैं। मानचित्र पर एक सर्कल बनाने के लिए, लेकिन अक्षांश/देशांतर में दिए गए निर्देशांक के साथ हमें विरूपण को उलटा करने की आवश्यकता है।

सबसे पहले हम रेडियंस में सर्कल का केंद्र पाते हैं - यह बहुत आसान है और lat और lon में संग्रहीत है।

फिर हम इसके किनारे पर सर्कल खोजने वाले बिंदुओं के चारों ओर जाते हैं। हम एक भौतिक चक्र बना रहे थे, तो अक्षांश और प्रत्येक बिंदु के देशांतर बस है:

 double latPoint = lat + (radius/EARTH_RADIUS) * Math.sin(t); 
     double lonPoint = lon + (radius/EARTH_RADIUS) * Math.cos(t); 

बहुत सरल त्रिकोणमिति है यही कारण है कि। (त्रिज्या/EARTH_RADIUS) रेडियंस में सर्कल के कोणीय त्रिज्या है (उदाहरण के लिए 100 मीटर की त्रिज्या वाला सर्कल 0.000015 रेड का कोणीय त्रिज्या होगा)।

अगर हम सरल कोड हम पाते हैं कि उस चक्र को नक्शे पर दिखाया cos(lat) द्वारा क्षैतिज squished था, इसलिए हम बस इसे unsquish को cos(lat) से विभाजित किया करते थे।

हम समान रूप से यह किया जा सकता था किया है:

 double latPoint = lat + (radius/EARTH_RADIUS) * Math.sin(t) * Math.cos(lat); 
     double lonPoint = lon + (radius/EARTH_RADIUS) * Math.cos(t); 

एक बड़े घेरे में परिणामस्वरूप - यह radius समारोह पैरामीटर अक्षांश या देशांतर को संदर्भित करता है कि क्या निर्भर करता है।

यह स्पष्टीकरण कुछ आरेखों का उपयोग कर सकता है लेकिन मुझे परेशान नहीं किया जा सकता है, क्षमा करें।

+0

क्या आप यहां गणित की व्याख्या कर सकते हैं? – Sulby

+0

मैंने थोड़ा सा स्पष्टीकरण जोड़ा है। – Timmmm

7

एंड्रॉइड 2.0 एपीआई आप मंडल को आकर्षित करने के लिए सर्कलऑप्शन का उपयोग कर सकते हैं, वास्तव में अच्छी तरह से काम करता है, पिक्सेल के मीटर में कोई गंदे रूपांतरण नहीं।

public CircleOptions getCircleOptions() { 
    CircleOptions co = new CircleOptions(); 
    co.center(latlng); 
    co.radius(getCircleSize()); 
    co.fillColor(getCircleColor()); 
    co.strokeColor(getStrokeColor()); 
    co.strokeWidth(2.0f); 
    return co; 
} 

    Circle circle = mapView.getMap().addCircle(munzeeMarker.getCircleOptions()); 
21

Google बनाया गया मानचित्र v2 में सरल है। नीचे स्निपेट ड्राइंग मार्कर और सर्कल दोनों को एक साथ अपनी स्थिति अपडेट करने के साथ प्रदर्शित करता है।

private Circle mCircle; 
private Marker mMarker; 
private GoogleMap mGoogleMap; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 

    mGoogleMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.mapFragment)).getMap(); 
    mGoogleMap.setMyLocationEnabled(true); 
    mGoogleMap.setOnMyLocationChangeListener(new GoogleMap.OnMyLocationChangeListener() { 
     @Override 
     public void onMyLocationChange(Location location) { 
      LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude()); 
      if(mCircle == null || mMarker == null){ 
       drawMarkerWithCircle(latLng); 
      }else{ 
       updateMarkerWithCircle(latLng); 
      } 
     } 
    }); 
} 

private void updateMarkerWithCircle(LatLng position) { 
    mCircle.setCenter(position); 
    mMarker.setPosition(position); 
} 

private void drawMarkerWithCircle(LatLng position){ 
    double radiusInMeters = 100.0; 
    int strokeColor = 0xffff0000; //red outline 
    int shadeColor = 0x44ff0000; //opaque red fill 

    CircleOptions circleOptions = new CircleOptions().center(position).radius(radiusInMeters).fillColor(shadeColor).strokeColor(strokeColor).strokeWidth(8); 
    mCircle = mGoogleMap.addCircle(circleOptions); 

    MarkerOptions markerOptions = new MarkerOptions().position(position); 
    mMarker = mGoogleMap.addMarker(markerOptions); 
} 
संबंधित मुद्दे