【问题标题】:draw circle with transparency in mapview在地图视图中绘制具有透明度的圆圈
【发布时间】:2013-11-16 19:34:11
【问题描述】:

我对 mapview 和 Overlay 有疑问。

每次更改 GPS 位置时,我都必须在地图上画一个圆圈。 我在扩展覆盖的覆盖类中使用了方法绘制。 问题是我必须用透明度绘制这些圆圈,但是当圆圈在交点处相互重叠时,颜色会有所不同,因为存在 alpha 的总和。

我该如何解决?

这是我的覆盖类:

public class ImpactOverlay extends Overlay {

private static int CIRCLERADIUS = 0;
private GeoPoint geopoint;
private int myCircleRadius;
Point point = new Point();
Paint circle = new Paint(Paint.ANTI_ALIAS_FLAG);
private long systemTime= -1 ;



public ImpactOverlay(GeoPoint point, int myRadius) {

    geopoint = point;
    CIRCLERADIUS = myRadius; // assegna raggio del cerchio
}

@Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {

     // Transfrom geoposition to Point on canvas
     Projection projection = mapView.getProjection();
     projection.toPixels(geopoint, point);

     // the circle to mark the spot
     circle.setColor(Color.parseColor("#88ff0000"));
     circle.setAlpha(122); // trasparenza

     myCircleRadius = metersToRadius(CIRCLERADIUS, mapView,
     (double) geopoint.getLatitudeE6() / 1000000);

     canvas.drawCircle(point.x, point.y, myCircleRadius, circle);       

}



public static int metersToRadius(float meters, MapView map, double latitude) {
    return (int) (map.getProjection().metersToEquatorPixels(meters) * (1 / Math
            .cos(Math.toRadians(latitude))));
}

@Override
/* Implementa il doppio tap per eseguire zoom sulla mappa */
public boolean onTouchEvent(MotionEvent event, MapView mapView) {
    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        if ((System.currentTimeMillis() - systemTime) < 250) {
            mapView.getController().zoomIn();
        }
        systemTime = System.currentTimeMillis();
        break;
    }

    return false;
}
}

【问题讨论】:

    标签: android google-maps overlay android-mapview geometry


    【解决方案1】:
            CircleOptions circle = new CircleOptions();
            circle.center(new LatLng(latitude, longitude))
            .radius(1500)//in meters
            .strokeColor(Color.BLUE)//border color
            .strokeWidth(3.0f)//border width
            .fillColor(0x200000ff);//inside circle
            googleMap.addCircle(circle);//GoogleMap googleMap(initialize accordingly)
    

    【讨论】:

      【解决方案2】:

      一种可能性是剪掉与第二个圆圈相交的区域,伪代码:

      canvas.clipPath(circle2.toPath())
      canvas.draw(circle1)
      canvas.removeClip()
      canvas.draw(circle2)
      

      【讨论】:

      • circle1 留在第一个位置,而 circle2 留在第二个位置?当我画一个圆圈时,我不知道下一个位置
      【解决方案3】:

      剪辑时需要考虑交叉点,如下所示: .

      @Override
      public boolean draw(Canvas canvas, MapView mapView, boolean shadow,
                      long when) {
          Paint paint = new Paint();
          paint.setColor(Color.parseColor("#88ff0000"));
          paint.setAlpha(16); // quite transparent
          Point point = new Point();
          Point point2 = new Point();
          float radius = 50.0f;
      
          Projection projection = mapView.getProjection();
          projection.toPixels(mGpt, point);   // 1st GeoPoint
          projection.toPixels(mGpt2, point2); // 2nd GeoPoint
      
          Path path1 = new Path();
          Path path2 = new Path();
      
          path1.addCircle(point.x, point.y, radius, Direction.CW);   // 1st circle
          path2.addCircle(point2.x, point2.y, radius, Direction.CW); // 2nd circle
          canvas.save(); // save canvas without the clip region
          canvas.clipPath(path2, Region.Op.DIFFERENCE); // clip the region
          // to the whole view less where circle2 will be when it's drawn
          canvas.drawPath(path1, paint); // draw 1st circle minus where it overlaps
          canvas.restore();              // clear the clip region
          canvas.drawPath(path2, paint); // draw 2nd circle (unclipped)
          return false;
      }
      

      应该有效

      【讨论】:

      • 如果我同时画两个圆圈,但我每次使用“draw”方法只画一个圆圈,你的解决方案就有效。此外,一个圆圈可以与我在地图上绘制的许多圆圈重叠,而不仅仅是一个,所以使用前一点是不够的。所以我正在考虑两种解决方案,但我不知道是否以及如何实现。有可能,清除我必须画圆圈的地图部分吗?或者在地图上放置一个蒙版,在这个没有alpha的圆圈中绘制一个圆圈,然后使所有蒙版半透明?
      • 是的,我看到了你的困难 - 你正在绘制多个叠加层,每个新位置一个。即使您保存所有位置并将它们全部放在一个叠加层中,也会很困难,因为一个圆圈可能与另一个圆圈重叠。我没有想法-抱歉。
      • 无论如何谢谢。如果可能的话,投票给我的问题,因为我需要为我的论文解决这个问题。
      【解决方案4】:

      您无需事先知道有多少种形状。如果您使用单独的叠加层,您可以轻松地绘制每个叠加层并将相应的区域添加到剪切区域。

      完整代码如下:

      import java.util.List;
      
      import android.graphics.*;
      import android.graphics.Path.Direction;
      import android.graphics.Region.Op;
      import android.os.Bundle;
      import android.view.MotionEvent;
      
      import com.google.android.maps.*;
      
      public class CircleTest extends MapActivity {
          private MapView m_map;
      
          @Override
          public void onCreate(final Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
      
              m_map = (MapView) findViewById(R.id.mapview);
              m_map.displayZoomControls(true);
              m_map.setBuiltInZoomControls(true);
          }
      
          @Override
          protected void onStart() {
              super.onStart();
              // m_map.getOverlays().add(new ); // some other overlays
              m_map.getOverlays().add(new ImpactGeneratorOverlay());
              // the impact areas are being inserted between these two, see ImpactGeneratorOverlay
              m_map.getOverlays().add(new ImpactClipRestoreOverlay());
          }
      
          /**
           * Restore clipping area to the saved one.
           */
          public static class ImpactClipRestoreOverlay extends Overlay {
              @Override
              public void draw(final Canvas canvas, final MapView mapView, final boolean shadow) {
                  super.draw(canvas, mapView, shadow);
                  canvas.restore();
              }
          }
      
          /**
           * Handles events, on touch down it adds a new Impact area to the map,
           * just before the ClipRestore overlay (assume it's the last, if not store position, and insert before).
           */
          public static class ImpactGeneratorOverlay extends Overlay {
              @Override
              public void draw(final Canvas canvas, final MapView mapView, final boolean shadow) {
                  super.draw(canvas, mapView, shadow);
                  canvas.save();
              }
      
              @Override
              public boolean onTouchEvent(final MotionEvent e, final MapView mapView) {
                  switch (e.getActionMasked()) {
                      case MotionEvent.ACTION_DOWN:
                          GeoPoint point = mapView.getProjection().fromPixels((int) e.getX(), (int) e.getY());
                          List<Overlay> overlays = mapView.getOverlays();
                          overlays.add(overlays.size() - 1, new ImpactOverlay(point, 1000));
                          break;
                  }
                  return super.onTouchEvent(e, mapView);
              }
          }
      
          /**
           * Draw impact and remove the current shape path from the drawable area.
           */
          public static class ImpactOverlay extends Overlay {
              // shape parameters
              private final GeoPoint  circleCenter;
              private final int       circleRadius;
      
              // drawing cache
              private final Point     circleDrawCenter    = new Point();
              private final Paint     circlePaint         = new Paint();
      
              public ImpactOverlay(final GeoPoint circleCenter, final int circleRadius) {
                  this.circleCenter = circleCenter;
                  this.circleRadius = circleRadius;
      
                  circlePaint.setAntiAlias(true);
                  circlePaint.setColor(Color.argb(64, 255, 0, 0));
              }
      
              @Override
              public void draw(final Canvas canvas, final MapView mapView, final boolean shadow) {
                  // Transfrom geoposition to Point on canvas
                  Projection projection = mapView.getProjection();
                  projection.toPixels(circleCenter, circleDrawCenter);
      
                  // the circle to mark the spot
                  float circleDrawRadius = ImpactOverlay.metersToRadius(mapView, circleRadius, circleCenter.getLatitudeE6() / 1e6f);
      
                  // create circle from path
                  Path path = new Path();
                  path.addCircle(circleDrawCenter.x, circleDrawCenter.y, circleDrawRadius, Direction.CW);
      
                  // draw circle
                  canvas.drawPath(path, circlePaint);
      
                  // remove circle from further posibble drawing areas
                  canvas.clipPath(path, Op.DIFFERENCE);
              }
      
              public static float metersToRadius(final MapView map, final float meters, final float latitude) {
                  return (float) (map.getProjection().metersToEquatorPixels(meters) * (1 / Math.cos(Math.toRadians(latitude))));
              }
          }
      
          @Override
          protected boolean isRouteDisplayed() {
              return false;
          }
      }
      

      这包含一个用于剪裁不需要的图层的修复程序,比如第一个,但是如果您只是将所有圆圈收集在一个叠加层中并在一个绘制方法中绘制它们,则可以避免这种情况。

      关键是绘制和设置剪辑(即使它们存在于不同的叠加层中,也不建议!):

      canvas.save();
      canvas.drawPath(path1, paint);
      canvas.clipPath(path1, Op.DIFFERENCE);
      canvas.drawPath(path2, paint); // do not draw over path1
      canvas.clipPath(path2, Op.DIFFERENCE);
      canvas.drawPath(path3, paint); // do not draw over path1 + path2
      canvas.clipPath(path3, Op.DIFFERENCE);
      // do not draw over path1 + path2 + path3
      canvas.restore();
      canvas.drawPath(path4, paint); // draw over anything
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-11-25
        • 1970-01-01
        • 1970-01-01
        • 2018-04-02
        • 1970-01-01
        • 2015-01-26
        • 2020-08-25
        • 1970-01-01
        相关资源
        最近更新 更多