fix: 增加根据轨迹复制图片的功能

This commit is contained in:
xiaoyan 2023-05-10 14:40:04 +08:00
parent eb7adc487d
commit 9d8185a958
4 changed files with 269 additions and 6 deletions

View File

@ -1,6 +1,7 @@
package com.navinfo.outdoor.activity;
import android.annotation.SuppressLint;
import android.app.DatePickerDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@ -16,6 +17,7 @@ import android.os.Handler;
import android.os.Message;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Pair;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
@ -23,6 +25,7 @@ import android.view.WindowManager;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.DatePicker;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RadioButton;
@ -43,6 +46,9 @@ import com.navinfo.outdoor.R;
import com.navinfo.outdoor.api.Constant;
import com.navinfo.outdoor.api.UserApplication;
import com.navinfo.outdoor.base.BaseActivity;
import com.navinfo.outdoor.bean.LocationRecorder;
import com.navinfo.outdoor.room.LocationRecorderDao;
import com.navinfo.outdoor.room.PoiDatabase;
import com.navinfo.outdoor.room.PoiEntity;
import com.navinfo.outdoor.util.AWMp4ParserHelper;
import com.navinfo.outdoor.util.BackHandlerHelper;
@ -77,6 +83,7 @@ import com.tencent.tencentmap.mapsdk.maps.UiSettings;
import com.tencent.tencentmap.mapsdk.maps.interfaces.Removable;
import com.tencent.tencentmap.mapsdk.maps.model.BitmapDescriptor;
import com.tencent.tencentmap.mapsdk.maps.model.BitmapDescriptorFactory;
import com.tencent.tencentmap.mapsdk.maps.model.CamerParameter;
import com.tencent.tencentmap.mapsdk.maps.model.CameraPosition;
import com.tencent.tencentmap.mapsdk.maps.model.LatLng;
import com.tencent.tencentmap.mapsdk.maps.model.Marker;
@ -104,12 +111,14 @@ import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import static com.tencent.tencentmap.mapsdk.maps.model.MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE;
import static com.tencent.tencentmap.mapsdk.maps.model.MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER;
@ -121,7 +130,7 @@ import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Action;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Predicate;
import io.reactivex.schedulers.Schedulers;
/**
@ -133,7 +142,7 @@ public class PicturesActivity extends BaseActivity implements View.OnClickListen
private CameraView camera;
private TencentMap tencentMap;
private TextureMapView tvMapView;
private List<Removable> removables;
private List<Removable> removables, trackRemovableList;
private Polyline polyline;
private String finalVideoPath, geoWkt, detail; // 摄像后最终保存的文件名
private ViewGroup layerChange; // 切换地图和相机的父控件
@ -185,6 +194,13 @@ public class PicturesActivity extends BaseActivity implements View.OnClickListen
});
private boolean booleanExtra;
private ImageView imgLocationType; // 切换定位方式
private ImageView imgTrackSelectRange, imgTrackSelectConfirm; // 自助选择轨迹对应照片
private LocationRecorderDao recorderDao;
private BitmapDescriptor trackDescriptor = BitmapDescriptorFactory
.fromResource(R.drawable.ic_baseline_arrow_drop_up_24);
private BitmapDescriptor pileDescriptor = BitmapDescriptorFactory
.fromResource(R.drawable.circle);
private long trackStartTime, trackEndTime;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
@ -197,6 +213,7 @@ public class PicturesActivity extends BaseActivity implements View.OnClickListen
setWindowBrightness(BRIGHTNESS);
LocationLifeCycle.getInstance().startGPSLocation();
speedCheck = new PicturesSpeedCheck();
recorderDao = PoiDatabase.getInstance(PicturesActivity.this).getRecorderDao();
}
@Override
@ -229,6 +246,7 @@ public class PicturesActivity extends BaseActivity implements View.OnClickListen
}
formatter = new SimpleDateFormat("yyyyMMdd HHmmss");
removables = new ArrayList<>();//存储轨迹的marker
trackRemovableList = new ArrayList<>(); // 存储自动捕捉时的轨迹marker
layerChange = findViewById(R.id.layer_change);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
systemTTS = SystemTTS.getInstance(PicturesActivity.this);
@ -483,6 +501,53 @@ public class PicturesActivity extends BaseActivity implements View.OnClickListen
});
imgLocationType = findViewById(R.id.img_location_type);
imgLocationType.setOnClickListener(this::onClick);
imgTrackSelectRange = findViewById(R.id.img_track_select_point);
imgTrackSelectRange.setOnClickListener(this::onClick);
imgTrackSelectConfirm = findViewById(R.id.img_track_select_confirm);
imgTrackSelectConfirm.setOnClickListener(this::onClick);
tencentMap.setOnMarkerClickListener(new TencentMap.OnMarkerClickListener() {
@Override
public boolean onMarkerClick(Marker marker) {
if (marker.getTag() instanceof LocationRecorder) {
LocationRecorder locationRecorder = (LocationRecorder) marker.getTag();
// 设置为起点或终点
MessageDialog.show(PicturesActivity.this, "选择起终点", "当前点位时间为:"+ formatter.format(new Date(locationRecorder.getTime()))+",设置为起点或终点",
"起点", "取消", "终点")
.setOnOkButtonClickListener(new OnDialogButtonClickListener() {
@Override
public boolean onClick(BaseDialog baseDialog, View v) {
// 设置该点位起点
if (trackEndTime!=0&&trackStartTime>=locationRecorder.getTime()) {
ToastUtils.Message(PicturesActivity.this, "开始时间不能在结束时间之后!");
} else {
trackStartTime = locationRecorder.getTime();
marker.setIcon(pileDescriptor);
}
return false;
}
})
.setOnCancelButtonClickListener(new OnDialogButtonClickListener() {
@Override
public boolean onClick(BaseDialog baseDialog, View v) {
return false;
}
})
.setOnOtherButtonClickListener(new OnDialogButtonClickListener() {
@Override
public boolean onClick(BaseDialog baseDialog, View v) {
if (trackStartTime!=0&&locationRecorder.getTime()<=trackStartTime) {
ToastUtils.Message(PicturesActivity.this, "结束时间不能在开始时间之前!");
} else {
trackEndTime = locationRecorder.getTime();
marker.setIcon(pileDescriptor);
}
return false;
}
});
}
return false;
}
});
}
class Jpg2WebpRunnable implements Runnable {
@ -725,6 +790,182 @@ public class PicturesActivity extends BaseActivity implements View.OnClickListen
LocationLifeCycle.getInstance().setMainLocationFrom(LocationLifeCycle.LOCATION_FROM.TENCENT);
ToastUtils.Message(PicturesActivity.this, "切换为网络定位");
}
break;
case R.id.img_track_select_point: // 切换显示自动捕捉时的轨迹信息
imgTrackSelectRange.setSelected(!imgTrackSelectRange.isSelected());
if (imgTrackSelectRange.isSelected()) { // 已选中
setLocMarkerStyle(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER);
Calendar mCalendar = Calendar.getInstance();
// 地图上显示轨迹
// 创建 DatePickerDialog 实例
DatePickerDialog datePickerDialog = new DatePickerDialog(
PicturesActivity.this,
new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker datePicker, int year, int month, int dayOfMonth) {
// 获取到年月日根据日期获取指定日期内的所有轨迹信息
// 更新当前选择的日期
mCalendar.set(Calendar.YEAR, year);
mCalendar.set(Calendar.MONTH, month);
mCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
// 获取最早时间戳当天的0点0分0秒
mCalendar.set(Calendar.HOUR_OF_DAY, 0);
mCalendar.set(Calendar.MINUTE, 0);
mCalendar.set(Calendar.SECOND, 0);
mCalendar.set(Calendar.MILLISECOND, 0);
long earliestTimestamp = mCalendar.getTimeInMillis();
// 获取最晚时间戳当天的23点59分59秒999毫秒
mCalendar.set(Calendar.HOUR_OF_DAY, 23);
mCalendar.set(Calendar.MINUTE, 59);
mCalendar.set(Calendar.SECOND, 59);
mCalendar.set(Calendar.MILLISECOND, 999);
long latestTimestamp = mCalendar.getTimeInMillis();
// 根据最早和最晚时间戳读取LocationRecorder数据表的数据
showLoadingDialog();
Observable.create(new ObservableOnSubscribe<List<LocationRecorder>>() {
@Override
public void subscribe(ObservableEmitter<List<LocationRecorder>> emitter) throws Exception {
List<LocationRecorder> locationRecorderByTime = recorderDao.getLocationRecorderByTime(earliestTimestamp, latestTimestamp);
emitter.onNext(locationRecorderByTime);
emitter.onComplete();
}
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new io.reactivex.functions.Consumer<List<LocationRecorder>>() {
@Override
public void accept(List<LocationRecorder> locationRecorderByTime) throws Exception {
if (locationRecorderByTime==null||locationRecorderByTime.isEmpty()) {
ToastUtils.Message(PicturesActivity.this, "该时间段内没有可用的轨迹数据");
} else {
tencentMap.animateCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition(
new LatLng(locationRecorderByTime.get(0).getTencentLocationY(), locationRecorderByTime.get(0).getTencentLocationX()), //中心点坐标地图目标经纬度
17, //目标缩放级别
0, //目标倾斜角[0.0 ~ 45.0] (垂直地图时为0)
0)), new TencentMap.CancelableCallback() {
@Override
public void onFinish() {
// 显示轨迹
for (int i = 0; i < locationRecorderByTime.size()&&i<4000; i++) {
LocationRecorder locationRecorder = locationRecorderByTime.get(i);
Marker marker = tencentMap.addMarker(new MarkerOptions(new LatLng(locationRecorder.getTencentLocationY(), locationRecorder.getTencentLocationX()))
// .icon(trackDescriptor)
// .rotation((float) locationRecorder.getBearing())
// .alpha(0.9f)
// .flat(true)
.tag(locationRecorder)
// .clockwise(false)
);
trackRemovableList.add(marker);
}
// for (LocationRecorder locationRecorder: locationRecorderByTime) {
// Marker marker = tencentMap.addMarker(new MarkerOptions(new LatLng(locationRecorder.getTencentLocationY(), locationRecorder.getTencentLocationX()))
//// .icon(trackDescriptor)
//// .rotation((float) locationRecorder.getBearing())
//// .alpha(0.9f)
//// .flat(true)
//// .tag(locationRecorder)
//// .clockwise(false)
// );
// trackRemovableList.add(marker);
// }
dismissLoadingDialog();
}
@Override
public void onCancel() {
}
}); //目标旋转角 0~360° (正北方为0));
}
}
});
}
},
mCalendar.get(Calendar.YEAR),
mCalendar.get(Calendar.MONTH),
mCalendar.get(Calendar.DAY_OF_MONTH)
);
// 显示 DatePickerDialog
datePickerDialog.show();
} else { // 未选中
setLocMarkerStyle(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE);
// 地图上隐藏轨迹
trackRemovableList.stream().forEach(new Consumer<Removable>() {
@Override
public void accept(Removable removable) {
removable.remove();
}
});
trackRemovableList.clear();
trackStartTime = 0;
trackEndTime = 0;
}
break;
case R.id.img_track_select_confirm:
// 用户确认从该时间段内选择照片
if (trackStartTime <= 0 || trackEndTime<=0 || trackStartTime >= trackEndTime) {
ToastUtils.Message(PicturesActivity.this, "起止时间选择有误,请确认!");
return;
}
Observable.create(new ObservableOnSubscribe<Pair<Integer, LocationRecorder>>() {
@Override
public void subscribe(ObservableEmitter<Pair<Integer, LocationRecorder>> emitter) throws Exception {
List<LocationRecorder> locationRecorderByTime = recorderDao.getLocationRecorderByTime(trackStartTime, trackEndTime);
final int[] index = {0};
locationRecorderByTime.forEach(new Consumer<LocationRecorder>() {
@Override
public void accept(LocationRecorder locationRecorder) {
if (new File(locationRecorder.getImgFileName()).exists()) {
emitter.onNext(new Pair<Integer, LocationRecorder>(index[0]++, locationRecorder));
}
}
});
emitter.onComplete();
}
}).subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.doOnNext(new io.reactivex.functions.Consumer<Pair<Integer, LocationRecorder>>() {
@Override
public void accept(Pair<Integer, LocationRecorder> integerLocationRecorderPair) throws Exception {
// 转移图片文件
File pictureFolder = new File(finalVideoPath).getParentFile();
File originImg = new File(integerLocationRecorderPair.second.getImgFileName());
File destFile = new File(pictureFolder.getParentFile().getAbsolutePath()+"/"+integerLocationRecorderPair.first+".jpg");
if (!destFile.exists()) {
FileUtils.copyFile(originImg.getAbsolutePath(), destFile.getAbsolutePath());
}
FileUtils.writeFile(paperFile.getAbsolutePath(), integerLocationRecorderPair.second.toString(formatter ,integerLocationRecorderPair.first), true);
}
}).subscribe(new Observer<Pair<Integer, LocationRecorder>>() {
@Override
public void onSubscribe(Disposable d) {
showLoadingDialog();
File pictureFolder = new File(finalVideoPath).getParentFile();
FileUtils.deleteFile(pictureFolder.getAbsolutePath());
if (!pictureFolder.exists()) {
pictureFolder.mkdirs();
}
paperFile.delete();
}
@Override
public void onNext(Pair<Integer, LocationRecorder> integerLocationRecorderPair) {
setLoadingDialogText("处理中:"+integerLocationRecorderPair.first);
}
@Override
public void onError(Throwable e) {
dismissLoadingDialog();
}
@Override
public void onComplete() {
dismissLoadingDialog();
}
});
break;
}
}
@ -1177,8 +1418,6 @@ public class PicturesActivity extends BaseActivity implements View.OnClickListen
} else {
latLng = new LatLng(LocationLifeCycle.getInstance().getTencentLocation().getLatitude(), LocationLifeCycle.getInstance().getTencentLocation().getLongitude());
}
BitmapDescriptor pileDescriptor = BitmapDescriptorFactory
.fromResource(R.drawable.circle);
Marker marker = tencentMap.addMarker(new MarkerOptions(latLng)
.icon(pileDescriptor)
.alpha(0.9f)

View File

@ -2,9 +2,9 @@ package com.navinfo.outdoor.http;
public class HttpInterface {
// public static final String IP = "http://172.23.138.133:9999/m4";//测试接口-IP
public static final String IP0 = "http://dtxbmaps.navinfo.com/dtxb/dev/m4";//开发接口-外网
public static final String IP = "http://dtxbmaps.navinfo.com/dtxb/dev/m4";//开发接口-外网
public static final String IP1 = "http://dtxbmaps.navinfo.com/dtxb/test/m4";//测试接口-外网
public static final String IP = "http://dtxbmaps.navinfo.com/dtxb/m4";//正式接口
public static final String IP0 = "http://dtxbmaps.navinfo.com/dtxb/m4";//正式接口
public static final String USER_PATH = "/user/";//我的
public static final String MSG_LIST_PATH = "/msgList/";//发现
public static final String USER_LOGIN_PATH = "/userlogin/";//登录

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#460D0D"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M7,14l5,-5 5,5z"/>
</vector>

View File

@ -173,6 +173,25 @@
android:layout_marginTop="@dimen/default_widget_padding"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_setting"></ImageView>
<ImageView
android:id="@+id/img_track_select_point"
android:layout_width="@dimen/default_round_widget"
android:layout_height="@dimen/default_round_widget"
android:background="@drawable/selector_round_bg"
android:text="从轨迹选择"
android:src="@drawable/selector_location_type"
android:padding="@dimen/default_widget_padding"
android:layout_marginTop="@dimen/default_widget_padding"></ImageView>
<ImageView
android:id="@+id/img_track_select_confirm"
android:layout_width="@dimen/default_round_widget"
android:layout_height="@dimen/default_round_widget"
android:background="@drawable/selector_round_bg"
android:text="确认轨迹选择时间"
android:src="@drawable/selector_location_type"
android:padding="@dimen/default_widget_padding"
android:layout_marginTop="@dimen/default_widget_padding"></ImageView>
</LinearLayout>
<RadioGroup