diff --git a/app/build.gradle b/app/build.gradle index ab7fa750..03268d5c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -127,6 +127,10 @@ dependencies { implementation "androidx.camera:camera-view:1.0.0-alpha24" implementation 'com.google.mlkit:barcode-scanning:16.1.1' + + //图片加载 + implementation 'com.github.bumptech.glide:glide:4.15.1' + annotationProcessor 'com.github.bumptech.glide:compiler:4.15.1' } //允许引用生成的代码 kapt { diff --git a/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainActivity.kt b/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainActivity.kt index e9d14e89..2234802e 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainActivity.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainActivity.kt @@ -184,8 +184,39 @@ class MainActivity : BaseActivity() { } //捕捉列表变化回调 viewModel.liveDataQsRecordIdList.observe(this) { - //处理页面跳转 - viewModel.navigationRightFragment(this, it) + //跳转到质检数据页面 + //获取右侧fragment容器 + val naviController = findNavController(R.id.main_activity_right_fragment) + + naviController.currentDestination?.let { navDestination -> + when (navDestination.id) { + R.id.RightEmptyFragment -> { + if (it.size == 1) { + val bundle = Bundle() + bundle.putString("QsId", it[0]) + naviController.navigate(R.id.EvaluationResultFragment, bundle) + } + } + } + } + } + //捕捉列表变化回调 + viewModel.liveDataNoteIdList.observe(this) { + //跳转到质检数据页面 + //获取右侧fragment容器 + val naviController = findNavController(R.id.main_activity_right_fragment) + + naviController.currentDestination?.let { navDestination -> + when (navDestination.id) { + R.id.RightEmptyFragment -> { + if (it.size == 1) { + val bundle = Bundle() + bundle.putString("NoteId", it[0]) + naviController.navigate(R.id.NoteFragment, bundle) + } + } + } + } } //右上角菜单是否被点击 viewModel.liveDataMenuState.observe(this) { @@ -253,7 +284,7 @@ class MainActivity : BaseActivity() { } } - viewModel.liveDataSignMoreInfo.observe(this){ + viewModel.liveDataSignMoreInfo.observe(this) { val fragment = supportFragmentManager.findFragmentById(R.id.main_activity_sign_more_info_fragment) if (fragment == null) { @@ -432,10 +463,17 @@ class MainActivity : BaseActivity() { /** * 隐藏或显示右侧展开按钮 */ - fun setRightSwitchButton(visibility: Int) { + fun setRightSwitchButtonVisibility(visibility: Int) { binding.mainActivityFragmentSwitch.visibility = visibility } + /** + * 顶部菜单按钮 + */ + fun setTopMenuButtonVisibility(visibility: Int) { + binding.mainActivityMenu.visibility = visibility + } + /** * 点击录音按钮 */ @@ -557,4 +595,20 @@ class MainActivity : BaseActivity() { viewModel.showSignMoreInfo(viewModel.liveDataRoadName.value!!) } } + + /** + * 新增便签,打开便签fragment + */ + fun onClickNewNote() { + rightController.navigate(R.id.NoteFragment) + binding.mainActivityMenu.isSelected = false + binding.mainActivityMenuGroup.visibility = View.INVISIBLE + } + + /** + * 右侧按钮+经纬度按钮 + */ + fun setRightButtonsVisible(visible: Int) { + binding.mainActivityRightVisibilityButtonsGroup2.visibility = visible + } } \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainViewModel.kt b/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainViewModel.kt index b456f1b1..33720482 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainViewModel.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainViewModel.kt @@ -71,6 +71,9 @@ class MainViewModel @Inject constructor( //地图点击捕捉到的质检数据ID列表 val liveDataQsRecordIdList = MutableLiveData>() + //地图点击捕捉到的标签ID列表 + val liveDataNoteIdList = MutableLiveData>() + //左侧看板数据 val liveDataSignList = MutableLiveData>() @@ -128,6 +131,10 @@ class MainViewModel @Inject constructor( override fun onQsRecordList(list: MutableList) { liveDataQsRecordIdList.value = list } + + override fun onNoteList(list: MutableList) { + liveDataNoteIdList.value = list + } }) initLocation() //处理地图点击操作 @@ -295,7 +302,8 @@ class MainViewModel @Inject constructor( } } - liveDataTopSignList.postValue(topSignList.distinctBy { it.name }.sortedBy { it.index }) + liveDataTopSignList.postValue(topSignList.distinctBy { it.name } + .sortedBy { it.index }) liveDataSignList.postValue(signList.sortedBy { it.distance }) val speechText = SignUtil.getRoadSpeechText(topSignList) @@ -470,25 +478,6 @@ class MainViewModel @Inject constructor( } } - /** - * 处理页面调转 - */ - fun navigationRightFragment(activity: MainActivity, list: List) { - //获取右侧fragment容器 - val naviController = activity.findNavController(R.id.main_activity_right_fragment) - - naviController.currentDestination?.let { navDestination -> - when (navDestination.id) { - R.id.RightEmptyFragment -> { - if (list.size == 1) { - val bundle = Bundle() - bundle.putString("QsId", list[0]) - naviController.navigate(R.id.EvaluationResultFragment, bundle) - } - } - } - } - } /** * 开启线选择 diff --git a/app/src/main/java/com/navinfo/omqs/ui/fragment/empty/EmptyFragment.kt b/app/src/main/java/com/navinfo/omqs/ui/fragment/empty/EmptyFragment.kt index f449b3fc..0792fa32 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/fragment/empty/EmptyFragment.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/fragment/empty/EmptyFragment.kt @@ -32,18 +32,27 @@ class EmptyFragment : Fragment() { override fun onStart() { super.onStart() val currentDestination = findNavController().currentDestination - //有右侧面板的时候 - if (currentDestination?.label == "右侧空页面") { - currentDestinationLabel = "右侧空页面" - (activity as MainActivity).setRightSwitchButton(View.GONE) + currentDestination?.let { + //有右侧面板的时候 + currentDestinationLabel = it.label.toString() + if (it.label == "右侧空页面") { + (activity as MainActivity).setRightSwitchButtonVisibility(View.GONE) + (activity as MainActivity).setTopMenuButtonVisibility(View.VISIBLE) + } else if (it.label == "中间空页面") { + (activity as MainActivity).setRightButtonsVisible(View.VISIBLE) + } } + } override fun onStop() { super.onStop() //没有有右侧面板的时候 if (currentDestinationLabel == "右侧空页面") { - (activity as MainActivity).setRightSwitchButton(View.VISIBLE) + (activity as MainActivity).setRightSwitchButtonVisibility(View.VISIBLE) + (activity as MainActivity).setTopMenuButtonVisibility(View.GONE) + } else if (currentDestinationLabel == "中间空页面") { + (activity as MainActivity).setRightButtonsVisible(View.GONE) } } diff --git a/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/EvaluationResultFragment.kt b/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/EvaluationResultFragment.kt index 6dd0d883..270654cd 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/EvaluationResultFragment.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/EvaluationResultFragment.kt @@ -2,11 +2,14 @@ package com.navinfo.omqs.ui.fragment.evaluationresult import android.app.Activity import android.content.Intent +import android.graphics.Bitmap import android.os.Build import android.os.Bundle import android.provider.MediaStore import android.util.Log import android.view.* +import androidx.activity.result.ActivityResult +import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import androidx.databinding.DataBindingUtil import androidx.navigation.NavOptions @@ -27,6 +30,7 @@ import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint class EvaluationResultFragment : BaseFragment(), View.OnClickListener { private lateinit var binding: FragmentEvaluationResultBinding + private var mCameraLauncher: ActivityResultLauncher? = null /** * 和[PhenomenonFragment],[ProblemLinkFragment],[EvaluationResultFragment]共用同一个viewModel @@ -37,6 +41,23 @@ class EvaluationResultFragment : BaseFragment(), View.OnClickListener { PictureAdapter() } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + mCameraLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { result: ActivityResult -> + if (result.resultCode == Activity.RESULT_OK) { + // 处理相机返回的结果 + val extras = result.data!!.extras + val imageBitmap: Bitmap? = extras!!["data"] as Bitmap? + // 在这里处理图片数据 + if (imageBitmap != null) + viewModel.savePhoto(imageBitmap) + } + } + } + // private val args:EmptyFragmentArgs by navArgs() override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? @@ -62,7 +83,7 @@ class EvaluationResultFragment : BaseFragment(), View.OnClickListener { adapter.refreshData(it) } - binding.evaluationPictureViewpager + return binding.root } @@ -122,7 +143,7 @@ class EvaluationResultFragment : BaseFragment(), View.OnClickListener { val recyclerView = viewPager.getChildAt(0) as RecyclerView - recyclerView.setPadding(0, 0, width / 2, 0) + recyclerView.setPadding(0, 0, width / 2 - 30, 0) recyclerView.clipToPadding = false } }) @@ -373,18 +394,10 @@ class EvaluationResultFragment : BaseFragment(), View.OnClickListener { private fun takePhoto() { try { - val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE) - - val someActivityResultLauncher = - registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> - if (result.resultCode == Activity.RESULT_OK) { - val data: Intent? = result.data - // 处理返回的结果 - } - } - - someActivityResultLauncher.launch(intent) - + val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE) + if (takePictureIntent.resolveActivity(requireActivity().packageManager) != null) { + mCameraLauncher!!.launch(takePictureIntent) + } } catch (e: Exception) { Log.d("TTTT", e.toString()) } diff --git a/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/EvaluationResultViewModel.kt b/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/EvaluationResultViewModel.kt index aa679ccb..a8b6ca0a 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/EvaluationResultViewModel.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/EvaluationResultViewModel.kt @@ -3,6 +3,7 @@ package com.navinfo.omqs.ui.fragment.evaluationresult import android.app.Activity import android.app.Dialog import android.content.Context +import android.graphics.Bitmap import android.graphics.drawable.AnimationDrawable import android.graphics.drawable.BitmapDrawable import android.os.Build @@ -35,17 +36,13 @@ import com.navinfo.omqs.util.DateTimeUtil import com.navinfo.omqs.util.SoundMeter import com.navinfo.omqs.util.SpeakMode import dagger.hilt.android.lifecycle.HiltViewModel -import io.realm.OrderedCollectionChangeSet import io.realm.Realm import io.realm.RealmList -import io.realm.RealmModel -import io.realm.RealmResults -import io.realm.kotlin.addChangeListener -import io.realm.kotlin.where import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.oscim.core.GeoPoint import java.io.File +import java.io.FileOutputStream import java.util.* import javax.inject.Inject @@ -78,9 +75,20 @@ class EvaluationResultViewModel @Inject constructor( */ val liveDataRightTypeList = MutableLiveData>() - var liveDataQsRecordBean = MutableLiveData() + /** + * + */ + val liveDataQsRecordBean = MutableLiveData() - var listDataChatMsgEntityList = MutableLiveData>() + /** + * 语音列表 + */ + val listDataChatMsgEntityList = MutableLiveData>() + + /** + * 照片列表 + */ + val liveDataPictureList = MutableLiveData>() var oldBean: QsRecordBean? = null @@ -520,9 +528,38 @@ class EvaluationResultViewModel @Inject constructor( mSoundMeter!!.stop() } pop?.let { - if(it.isShowing){ + if (it.isShowing) { it.dismiss() } } } + + + fun savePhoto(bitmap: Bitmap) { + viewModelScope.launch(Dispatchers.IO) { + // 创建一个名为 "MyApp" 的文件夹 + val myAppDir = File(Constant.USER_DATA_ATTACHEMNT_PATH) + if (!myAppDir.exists()) + myAppDir.mkdirs() // 确保文件夹已创建 + + // 创建一个名为 fileName 的文件 + val file = File(myAppDir, "${UUID.randomUUID()}.png") + file.createNewFile() // 创建文件 + + // 将 Bitmap 压缩为 JPEG 格式,并将其写入文件中 + val out = FileOutputStream(file) + bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out) + out.flush() + out.close() + var picList = mutableListOf() + if (liveDataPictureList.value == null) { + picList.add(file.absolutePath) + } else { + picList.addAll(liveDataPictureList.value!!) + picList.add(file.absolutePath) + } + liveDataPictureList.postValue(picList) + } + + } } \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/omqs/ui/fragment/note/CanvasFragment.kt b/app/src/main/java/com/navinfo/omqs/ui/fragment/note/CanvasFragment.kt new file mode 100644 index 00000000..09ca56e9 --- /dev/null +++ b/app/src/main/java/com/navinfo/omqs/ui/fragment/note/CanvasFragment.kt @@ -0,0 +1,154 @@ +package com.navinfo.omqs.ui.fragment.note + +import android.os.Build +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import com.navinfo.omqs.R +import com.navinfo.omqs.databinding.FragmentCanvasBinding +import com.navinfo.omqs.databinding.FragmentNoteBinding +import com.navinfo.omqs.databinding.FragmentProblemLinkBinding +import com.navinfo.omqs.ui.fragment.BaseFragment +import com.navinfo.omqs.ui.fragment.note.CanvasView.CanvasStyle +import com.navinfo.omqs.ui.fragment.note.CanvasView.OnCanvasChangeListener +import com.navinfo.omqs.ui.other.shareViewModels + +/** + * @author zhjch + * @version V1.0 + * @ClassName: CanvasFragment + * @Date 2016/5/10 + * @Description: ${TODO}(绘制画布) + */ +class CanvasFragment : BaseFragment() { + /** + * 获取画布 + * + * @return + */ + /** + * 画布 + */ + private val canvasView by lazy { binding.canvasView } + + /** + * 画笔线型 + */ + private var mStyle = CanvasStyle.FREE_LINE + + /** + * 画笔颜色 + */ + private var mColor = -1 + + /** + * 画笔粗细 + */ + private var width = 5 + + + /** + * 画布回调接口 + */ + private var listener: OnCanvasChangeListener? = null + + + private var _binding: FragmentCanvasBinding? = null + private val binding get() = _binding!! + + private val viewModel by shareViewModels("note") + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + _binding = FragmentCanvasBinding.inflate(inflater, container, false) + viewModel.initCanvasView(canvasView) + return binding.root + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + canvasView.setStyle(mStyle) + if (mColor == -1) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + mColor = resources.getColor(R.color.black, null) + } + } + canvasView.setPaintColor(mColor) + canvasView.setPaintWidth(width) + if (listener != null) { + canvasView.setOnCanvasChangeListener(listener) + } + +// * 开关橡皮擦 +// */ +// viewModel.liveEraserData.observe(viewLifecycleOwner) { +// canvasView.setEraser(it) +// } +// /** +// * 清除 +// */ +// viewModel.liveClearData.observe(viewLifecycleOwner) { +// canvasView.removeAllPaint() +// } +// /** +// * 回退上一笔 +// */ +// viewModel.liveBackData.observe(viewLifecycleOwner) { +// canvasView.back() +// } +// /** +// * 撤销回退 +// */ +// viewModel.liveForward.observe(viewLifecycleOwner) { +// canvasView.forward() +// } +// + + } + + + /** + * 将数据转化并绘制在画板上 + * + * @param value + */ + fun setDrawPathList(value: MutableList) { + if (value != null && value.isNotEmpty()) { + canvasView.setDrawPathList(value) + } + } + + + /** + * 设置草图画笔线型 + */ + fun setStyle(style: CanvasStyle) { + mStyle = style + canvasView.setStyle(style) + } + + /** + * 设置画笔颜色 + */ + fun setPaintColor(color: Int) { + mColor = color + canvasView.setPaintColor(mColor) + } + + /** + * 设置画笔粗细 + */ + fun setPaintWidth(width: Int) { + this.width = width + canvasView.setPaintWidth(width) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/omqs/ui/fragment/note/CanvasView.kt b/app/src/main/java/com/navinfo/omqs/ui/fragment/note/CanvasView.kt new file mode 100644 index 00000000..c8797d46 --- /dev/null +++ b/app/src/main/java/com/navinfo/omqs/ui/fragment/note/CanvasView.kt @@ -0,0 +1,1801 @@ +package com.navinfo.omqs.ui.fragment.note + +import android.content.Context +import android.graphics.* +import android.media.ThumbnailUtils +import android.util.AttributeSet +import android.util.Log +import android.view.MotionEvent +import android.view.View +import com.navinfo.collect.library.utils.GeometryTools +import com.navinfo.omqs.R +import com.navinfo.omqs.ui.other.BaseToast +import kotlin.math.abs +import kotlin.math.cos +import kotlin.math.sin + +/** + * @author zhjch + * @version V1.0 + * @ClassName: CanvasView + * @Date 2016/5/10 + * @Description: ${TODO}(画板) + */ +class CanvasView @JvmOverloads constructor( + private val mContext: Context, + attrs: AttributeSet? = null, + defStyle: Int = 0 +) : View( + mContext, attrs, defStyle +) { + /** + * 画笔类型 + */ + enum class CanvasStyle { + FREE_LINE, //自由线 + STRAIGHT_LINE, //直线 + RECT_LINE, //框 + RAILWAY_LINE, // 铁路线 + GREENLAND_LINE, //绿地线 + WATER_LINE, //水系线 + BUILDING_LINE, //建筑物 + POLY_LINE, //折线 + CIRCULAR_POINT, //圆点 + ELLIPSE_LINE, //椭圆 + PARKING_LINE + //停车场 + } + + /** + * 画布 + */ + private var mCanvas: Canvas? = null + + /** + * 控制线型 + */ + private var mPath: Path? = null + + /** + * 画布背景 + */ + private var mBitmapPaint: Paint? = null + + /** + * 画布前景 + */ + private var mBitmap: Bitmap? = null + + /** + * 普通画笔 + */ + private val mPaint: Paint? + + /** + * 圆形画笔 + */ + private val mPaintCircular: Paint + + /** + * 铁路画笔1 底色 + */ + private val mPaintRailway1: Paint + + /** + * 铁路画笔2 前景色 + */ + private val mPaintRailway2: Paint + + /** + * 水系画笔1 边框 + */ + private val mPaintWater: Paint + + /** + * 水系画笔2 填充 + */ + private val mPaintWater1: Paint + + /** + * 绿地画笔1 边框 + */ + private val mPaintGreenland: Paint + + /** + * 绿地画笔2 填充 + */ + private val mPaintGreenland1: Paint + + /** + * 停车场1 边框 + */ + private val mPaintParking: Paint + + /** + * 停车场 填充 + */ + private val mPaintParking1: Paint + + /** + * 准星图片 + */ + private val mStarBitmap: Bitmap + + /** + * 铁路栅格线样式 + */ + private val pathEffect1 = DashPathEffect(floatArrayOf(16f, 16f), 4f) + // private DashPathEffect pathEffect2 = new DashPathEffect(new float[] { 12,12 }, 12); + /** + * 需不需要记录画笔轨迹点 + */ + private var isSavePoint: Boolean + + /** + * 是否在move 中 + */ + private var isMove = false + + /** + * 是否打开橡皮擦 + */ + private var isEraser = false + + /** + * 绘制轨迹路径 + */ + private var mDrawPath: DrawPath? = null + + /** + * 画笔宽度 + */ + private var mPaintWidth = 5 + + /** + * 画笔颜色 + */ + private var mPaintColor = 0xFF5052 + + /** + * 圆形图案半径 + */ + private val mCircularP = 150 + /** + * 获取当前画笔样式 + * + * @return + */ + /** + * 线型 + */ + var canvasStyle = CanvasStyle.FREE_LINE + private set + + /** + * 当前画布上的每一笔 + */ + private var mCurrentPaths: MutableList = mutableListOf() + + /** + * 被撤销的每一笔 + */ + private val mDeletePaths: MutableList? + + /** + * 画布 宽度 + */ + private var viewWidth = 10 + + /** + * 画布 高度 + */ + private var viewHeight = 10 + + /** + * 画笔第一笔点下去的位置 + */ + private var mDownX = 0f + private var mDownY = 0f + + /** + * 画笔移动的位置 + */ + private var mMoveX = 0f + private var mMoveY = 0f + + /** + * 圆点图案移动矩阵 + */ + private val mMatrixCircular = Matrix() + private var mListener: OnCanvasChangeListener? = null + + /** + * 用来回馈上层页面 + */ + interface OnCanvasChangeListener { + /** + * 画布上有绘制操作 + */ + fun onDraw() + } + + fun setOnCanvasChangeListener(listener: OnCanvasChangeListener?) { + mListener = listener + } + + //路径对象 + class DrawPath( + startPoint: Point?, + var path: Path, + var width: Int, + var color: Int, + var style: CanvasStyle + ) { + var pointList: MutableList? + var isOver = true + + /** + * 外截矩形 + */ + var rect: Rect? = null + + /** + * @param startPoint 起点 + * @param path 路径 + * @param width 宽度 + * @param color 颜色 + * @param style 线型 + */ + init { + pointList = ArrayList() + if (startPoint != null) { + rect = Rect(startPoint.x, startPoint.y, startPoint.x + 1, startPoint.y + 1) + } + } + + /** + * 获取画笔 + * + * @param paint + * @return + */ + fun getPaint(paint: Paint?): Paint? { + paint!!.strokeWidth = width.toFloat() + paint.color = color + return paint + } + } + + /** + * 初始化画布 + */ + private fun initCanvas() { + //画布大小 + if (mBitmap != null) { + mBitmap!!.recycle() + } + mBitmap = Bitmap.createBitmap(viewWidth, viewHeight, Bitmap.Config.ARGB_8888) + mCanvas = Canvas(mBitmap!!) //所有mCanvas画的东西都被保存在了mBitmap中 + mPath = Path() + mBitmapPaint = Paint(Paint.DITHER_FLAG) + } + + /** + * 结束折线类型的操作 + */ + private fun setPolyLineOver() { + if (mCurrentPaths.size > 0) { + val path = mCurrentPaths[mCurrentPaths.size - 1] + if (path.style == CanvasStyle.RAILWAY_LINE + || path.style == CanvasStyle.POLY_LINE + ) { + //切换类型时,线少于2个点的不要 + if (path.pointList == null || path.pointList!!.size == 1) { + back() //只有一个点时会遗留一个起始圆点,先移除掉。然后清除 + mDeletePaths!!.clear() + if (path === mDrawPath) { + mDrawPath = null + // mDrawPath.pointList.clear(); +// mPath.reset(); + } + return + } + } else if (path.style == CanvasStyle.GREENLAND_LINE || path.style == CanvasStyle.WATER_LINE || path.style == CanvasStyle.PARKING_LINE) { + //切换类型时,面少于3个点的不要 + if (path.pointList == null || path.pointList!!.size < 4) { + mCurrentPaths.removeAt(mCurrentPaths.size - 1) + initCanvas() + } + invalidate() + return + } + path.isOver = true + } + } + + /** + * 切换线型 + * + * @param style + */ + fun setStyle(style: CanvasStyle) { + canvasStyle = style + setPolyLineOver() + } + + init { + mCurrentPaths = ArrayList() + mDeletePaths = ArrayList() + mPaint = Paint() + mPaint.isAntiAlias = true + mPaint.isDither = true + mPaint.color = mPaintColor + mPaint.style = Paint.Style.STROKE + mPaint.strokeJoin = Paint.Join.ROUND + mPaint.strokeCap = Paint.Cap.ROUND + mPaint.strokeWidth = mPaintWidth.toFloat() + mPaintRailway1 = Paint() + mPaintRailway1.isAntiAlias = true + mPaintRailway1.isDither = true + mPaintRailway1.color = -0xff8f40 + mPaintRailway1.style = Paint.Style.STROKE + mPaintRailway1.strokeWidth = 8f + mPaintRailway2 = Paint() + mPaintRailway2.isAntiAlias = true + mPaintRailway2.isDither = true + mPaintRailway2.color = Color.WHITE + mPaintRailway2.style = Paint.Style.STROKE + mPaintRailway2.strokeWidth = 4f + mPaintRailway2.pathEffect = pathEffect1 + mPaintWater = Paint() + mPaintWater.isAntiAlias = true + mPaintWater.isDither = true + mPaintWater.color = -0x543501 + mPaintWater.style = Paint.Style.FILL + mPaintWater.strokeWidth = 4f + mPaintWater1 = Paint() + mPaintWater1.isAntiAlias = true + mPaintWater1.isDither = true + mPaintWater1.color = -0xff4fb0 + mPaintWater1.style = Paint.Style.STROKE + mPaintWater1.strokeWidth = 4f + mPaintGreenland = Paint() + mPaintGreenland.isAntiAlias = true + mPaintGreenland.isDither = true + mPaintGreenland.color = -0x321c54 + mPaintGreenland.style = Paint.Style.FILL + mPaintGreenland.strokeWidth = 4f + mPaintGreenland1 = Paint() + mPaintGreenland1.isAntiAlias = true + mPaintGreenland1.isDither = true + mPaintGreenland1.color = -0xff4fb0 + mPaintGreenland1.style = Paint.Style.STROKE + mPaintGreenland1.strokeWidth = 4f + mPaintParking = Paint() + mPaintParking.isAntiAlias = true + mPaintParking.isDither = true + mPaintParking.color = -0x168 + mPaintParking.style = Paint.Style.FILL + mPaintParking.strokeWidth = 4f + mPaintParking1 = Paint() + mPaintParking1.isAntiAlias = true + mPaintParking1.isDither = true + mPaintParking1.color = -0x59595a + mPaintParking1.style = Paint.Style.STROKE + mPaintParking1.strokeWidth = 4f + mPaintCircular = Paint() + mPaintCircular.style = Paint.Style.FILL + mPaintCircular.color = mPaintColor + mStarBitmap = BitmapFactory.decodeResource(resources, R.drawable.home_map_center) + val a = mContext.obtainStyledAttributes(attrs, R.styleable.CanvasView) + isSavePoint = a.getBoolean(R.styleable.CanvasView_isSavePoint, true) + a.recycle() + } + + /** + * 手指移动的处理 + * + * @param x 坐标 + * @param y 坐标 + */ + private fun touch_move_line(x: Float, y: Float) { + if (x == mDownX && y == mDownY) return + val dx = abs(x - mDownX) + val dy = abs(y - mDownY) + if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) { + //增加非空判断 + if (mPath != null) mPath!!.quadTo( + mDownX, + mDownY, + (x + mDownX) / 2, + (y + mDownY) / 2 + ) //源代码是这样写的,可是我没有弄明白,为什么要这样? + mDownX = x + mDownY = y + } + setBuilder(x.toInt(), y.toInt()) + } + + /** + * 多边形起点点下时的处理 + * + * @param x 坐标 + * @param y 坐标 + */ + private fun touch_start_poly(x: Int, y: Int) { + if (canvasStyle == CanvasStyle.GREENLAND_LINE || canvasStyle == CanvasStyle.WATER_LINE || canvasStyle == CanvasStyle.PARKING_LINE) { + if (mCurrentPaths.size > 0 && mCurrentPaths[0].isOver) { + BaseToast.makeText(mContext, "不允许存在多个!", BaseToast.LENGTH_SHORT).show() + return + } + if (mCurrentPaths.size > 0) { + val drawPath = mCurrentPaths[mCurrentPaths!!.size - 1] + if (drawPath.pointList!!.size > 3) { + if (!GeometryTools.isSimplePolygon(drawPath.pointList, Point(x, y))) { + BaseToast.makeText(mContext, "面不允许自相交图形!", BaseToast.LENGTH_SHORT).show() + return + } + } + } + } + if (mDeletePaths != null && mDeletePaths.size > 0) { + mDeletePaths.clear() + } + if (mCurrentPaths.size > 0) { + val drawPath = mCurrentPaths[mCurrentPaths.size - 1] + if (!drawPath.isOver) { + mDrawPath = drawPath + if (drawPath.style == CanvasStyle.GREENLAND_LINE || drawPath.style == CanvasStyle.WATER_LINE || drawPath.style == CanvasStyle.PARKING_LINE) { + if (drawPath.pointList!!.size > 1) { + drawPath.pointList!!.removeAt(drawPath.pointList!!.size - 1) + } + setBuilder(x, y) + if (drawPath.pointList!!.size < 3) { + drawPath.path.lineTo(x.toFloat(), y.toFloat()) + } else { + initCanvas() + drawPath.path.reset() + for (i in drawPath.pointList!!.indices) { + if (i == 0) { + drawPath.path.moveTo( + drawPath.pointList!![0].x.toFloat(), + drawPath.pointList!![0].y.toFloat() + ) + } else { + drawPath.path.lineTo( + drawPath.pointList!![i].x.toFloat(), + drawPath.pointList!![i].y.toFloat() + ) + } + } + drawPath.path.lineTo( + drawPath.pointList!![0].x.toFloat(), + drawPath.pointList!![0].y.toFloat() + ) + } + drawPath.pointList!!.add(drawPath.pointList!![0]) + } else { + drawPath.path.lineTo(x.toFloat(), y.toFloat()) + setBuilder(x, y) + } + if (drawPath.style == CanvasStyle.POLY_LINE) { + mCanvas!!.drawPath(drawPath.path, drawPath.getPaint(mPaint)!!) + } else if (drawPath.style == CanvasStyle.RAILWAY_LINE) { + mCanvas!!.drawPath(drawPath.path, mPaintRailway1) + mCanvas!!.drawPath(drawPath.path, mPaintRailway2) + } else if (drawPath.style == CanvasStyle.GREENLAND_LINE) { + mCanvas!!.drawPath(drawPath.path, mPaintGreenland) + mCanvas!!.drawPath(drawPath.path, mPaintGreenland1) + } else if (drawPath.style == CanvasStyle.WATER_LINE) { + mCanvas!!.drawPath(drawPath.path, mPaintWater) + mCanvas!!.drawPath(drawPath.path, mPaintWater1) + } else if (drawPath.style == CanvasStyle.PARKING_LINE) { + mCanvas!!.drawPath(drawPath.path, mPaintParking) + mCanvas!!.drawPath(drawPath.path, mPaintParking1) + } + invalidate() + return + } + } + mPath = Path() + mDrawPath = DrawPath(Point(x, y), mPath!!, mPaintWidth, mPaintColor, canvasStyle) + mDrawPath!!.isOver = false + mPaintCircular.color = mPaintColor + mCanvas!!.drawCircle(x.toFloat(), y.toFloat(), 2f, mPaintCircular) + mPath!!.moveTo(x.toFloat(), y.toFloat()) + setBuilder(x, y) + if (canvasStyle == CanvasStyle.WATER_LINE || canvasStyle == CanvasStyle.GREENLAND_LINE || canvasStyle == CanvasStyle.PARKING_LINE) { + setBuilder(x, y) + } + mCurrentPaths.add(mDrawPath!!) + if (mListener != null) { + mListener!!.onDraw() + } + invalidate() + return + } + + /** + * 手指按下的第一个点处理 + * + * @param x 坐标 + * @param y 坐标 + */ + private fun touch_start(x: Float, y: Float) { + mPath!!.reset() //清空path + mPath!!.moveTo(x, y) + mDownX = x + mDownY = y + if (canvasStyle != CanvasStyle.ELLIPSE_LINE) setBuilder(x.toInt(), y.toInt()) + if (mDeletePaths != null && mDeletePaths.size > 0) { + mDeletePaths.clear() + } + } + + /** + * 手指离开屏幕时的处理 + * + * @param x 坐标 + * @param y 坐标 + */ + private fun touch_up(x: Float, y: Float) { + try { + if (canvasStyle == CanvasStyle.POLY_LINE) { + val Y = y - mCircularP + mStarBitmap.height / 2 + mDrawPath!!.width = mPaintWidth + mDrawPath!!.color = mPaintColor + if (mDrawPath!!.pointList!!.size > 0) { + mDrawPath = mCurrentPaths[mCurrentPaths.size - 1] + mPath = mDrawPath!!.path + mPath!!.lineTo(x, Y) + mCanvas!!.drawPath(mPath!!, mPaint!!) + } else { + mCurrentPaths.add(mDrawPath!!) + if (mListener != null) { + mListener!!.onDraw() + } + mPath!!.moveTo(x, Y) + mPaintCircular.color = mPaintColor + mPaintCircular.strokeWidth = 4f + mCanvas!!.drawCircle(x, Y, 4f, mPaintCircular) + } + setBuilder(x.toInt(), Y.toInt()) + return + } else if (canvasStyle == CanvasStyle.STRAIGHT_LINE) { + val Y = y - mCircularP + mStarBitmap.height / 2 + setBuilder(x.toInt(), Y.toInt()) + mDrawPath!!.width = mPaintWidth + mDrawPath!!.color = mPaintColor + if (mDrawPath!!.pointList!!.size > 1) { + mDrawPath!!.isOver = true + mCurrentPaths.add(mDrawPath!!) + if (mListener != null) { + mListener!!.onDraw() + } + mPath!!.lineTo(x, Y) + mCanvas!!.drawPath(mPath!!, mPaint!!) + mPath = null + } else { + mPath!!.moveTo(x, Y) + mPaintCircular.color = mPaintColor + mPaintCircular.strokeWidth = 4f + mCanvas!!.drawCircle(x, Y, 4f, mPaintCircular) + } + return + } else if (canvasStyle == CanvasStyle.CIRCULAR_POINT) { + mPaintCircular.color = mPaintColor + val Y = y - mCircularP + mStarBitmap.height / 2 + mCanvas!!.drawCircle(x, Y, (mPaintWidth + 5).toFloat(), mPaintCircular) + mDrawPath!!.pointList!!.add(Point(x.toInt(), Y.toInt())) + mDrawPath!!.rect = Rect( + (x - mPaintWidth - 20).toInt(), + (Y - mPaintWidth - 20).toInt(), + (x + mPaintWidth + 20).toInt(), + (Y + mPaintWidth + 20).toInt() + ) + mCurrentPaths.add(mDrawPath!!) + if (mListener != null) { + mListener!!.onDraw() + } + } else if (canvasStyle == CanvasStyle.RECT_LINE) { + if (mDownX == x || mDownY == y) return + mPath!!.lineTo(x, mDownY) + setBuilder(x.toInt(), mDownY.toInt()) + mPath!!.lineTo(x, y) + setBuilder(x.toInt(), y.toInt()) + mPath!!.lineTo(mDownX, y) + setBuilder(mDownX.toInt(), y.toInt()) + mPath!!.lineTo(mDownX, mDownY) + setBuilder(mDownX.toInt(), mDownY.toInt()) + } else if (canvasStyle == CanvasStyle.ELLIPSE_LINE) { + if (mDownX == x || mDownY == y) { + return + } + val minX = if (x < mDownX) x else mDownX + val maxX = if (x > mDownX) x else mDownX + val minY = if (y < mDownY) y else mDownY + val maxY = if (y > mDownY) y else mDownY + mPath!!.moveTo(minX, minY) + mPath!!.addOval(RectF(minX, minY, maxX, maxY), Path.Direction.CW) + var a = 0.0 + val xR = ((maxX - minX) / 2).toDouble() + val yR = ((maxY - minY) / 2).toDouble() + var tempX = (xR * cos(a) + xR + minX).toInt() + val tempY = (yR * sin(a) + yR + minY).toInt() + val firstX = tempX + setBuilder(tempX, tempY) + var bLeft = false + var bRight = false + while (!bLeft || !bRight) { + a += 0.1 + val x1 = (xR * Math.cos(a) + xR + minX).toInt() + val y1 = (yR * Math.sin(a) + yR + minY).toInt() + if (!bLeft && x1 > tempX) { + bLeft = true + } + if (!bRight && bLeft && x1 <= tempX) { + bRight = true + setBuilder(firstX, tempY) + } else { + tempX = x1 + setBuilder(x1, y1) + } + } + } else { + if (!contains( + mDownX.toInt(), + mDownY.toInt(), + x.toInt(), + y.toInt(), + ChouXiBanJing + ) + ) { + mPath!!.lineTo(x, y) + setBuilder(x.toInt(), y.toInt()) + } + if (canvasStyle == CanvasStyle.GREENLAND_LINE || canvasStyle == CanvasStyle.WATER_LINE || canvasStyle == CanvasStyle.PARKING_LINE) { + val point = mDrawPath!!.pointList!![0] + mPath!!.lineTo(point.x.toFloat(), point.y.toFloat()) + setBuilder(point.x, point.y) + } + } + if (mDrawPath!!.pointList!!.size > 1) { + if (canvasStyle == CanvasStyle.RAILWAY_LINE) { + mCanvas!!.drawPath(mPath!!, mPaintRailway1) + mCanvas!!.drawPath(mPath!!, mPaintRailway2) + } else if (canvasStyle == CanvasStyle.GREENLAND_LINE) { + mCanvas!!.drawPath(mPath!!, mPaintGreenland) + mCanvas!!.drawPath(mPath!!, mPaintGreenland1) + } else if (canvasStyle == CanvasStyle.WATER_LINE) { + mCanvas!!.drawPath(mPath!!, mPaintWater) + mCanvas!!.drawPath(mPath!!, mPaintWater1) + } else if (canvasStyle == CanvasStyle.PARKING_LINE) { + mCanvas!!.drawPath(mPath!!, mPaintParking) + mCanvas!!.drawPath(mPath!!, mPaintParking1) + } else { + mCanvas!!.drawPath(mPath!!, mPaint!!) + } + mCurrentPaths.add(mDrawPath!!) + if (mListener != null) { + mListener!!.onDraw() + } + } + mPath = null + } catch (e: Exception) { + } + } + + /** + * 记录每一个点,并计算外截矩形 + * + * @param x + * @param y + */ + private fun setBuilder(x: Int, y: Int) { + if (!isSavePoint || mDrawPath == null) return + if (mDrawPath!!.pointList == null) mDrawPath!!.pointList = ArrayList() + if (mDrawPath!!.rect == null) { + mDrawPath!!.rect = Rect(x, y, x + 1, y + 1) + } + if (x < mDrawPath!!.rect!!.left) { + mDrawPath!!.rect!!.left = x + } else if (x > mDrawPath!!.rect!!.right) { + mDrawPath!!.rect!!.right = x + } + if (y < mDrawPath!!.rect!!.top) { + mDrawPath!!.rect!!.top = y + } else if (y > mDrawPath!!.rect!!.bottom) { + mDrawPath!!.rect!!.bottom = y + } + mDrawPath!!.pointList!!.add(Point(x, y)) + } + + /** + * 记录手指滑动中的坐标 + * + * @param x + * @param y + */ + private fun touch_move(x: Float, y: Float) { + mMoveX = x + mMoveY = y + } + + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + viewWidth = w + viewHeight = h + initCanvas() + if (mCurrentPaths.isNotEmpty()) { + for (dp in mCurrentPaths) { + if (dp.style == CanvasStyle.RAILWAY_LINE) { + mCanvas!!.drawPath(dp.path, mPaintRailway1) + mCanvas!!.drawPath(dp.path, mPaintRailway2) + } else if (dp.style == CanvasStyle.GREENLAND_LINE) { + mCanvas!!.drawPath(dp.path, mPaintGreenland) + mCanvas!!.drawPath(dp.path, mPaintGreenland1) + } else if (dp.style == CanvasStyle.WATER_LINE) { + mCanvas!!.drawPath(dp.path, mPaintWater) + mCanvas!!.drawPath(mPath!!, mPaintWater1) + } else if (dp.style == CanvasStyle.PARKING_LINE) { + mCanvas!!.drawPath(dp.path, mPaintParking) + mCanvas!!.drawPath(mPath!!, mPaintParking1) + } else { + mCanvas!!.drawPath(dp.path, dp.getPaint(mPaint)!!) + } + } + } + } + + /** + * 撤销上一步 + */ + fun back(): Boolean { + if (mCurrentPaths.size > 0) { + //调用初始化画布函数以清空画布 + initCanvas() + //将路径保存列表中的最后一个元素删除 ,并将其保存在路径删除列表中 + val drawPath = mCurrentPaths[mCurrentPaths.size - 1] + //如果是正在绘制的折线 + if ((drawPath.style == CanvasStyle.POLY_LINE + || drawPath.style == CanvasStyle.RAILWAY_LINE) + && !drawPath.isOver + ) { + val drawPathCopy: DrawPath? + if (mDeletePaths!!.size == 0 || mDeletePaths[mDeletePaths.size - 1]!!.style != drawPath.style || mDeletePaths[mDeletePaths.size - 1]!!.isOver) { + drawPathCopy = DrawPath( + null, + drawPath.path, + drawPath.width, + drawPath.color, + drawPath.style + ) + drawPathCopy.rect = drawPath.rect + drawPathCopy.isOver = false + mDeletePaths.add(drawPathCopy) + } else { + drawPathCopy = mDeletePaths[mDeletePaths.size - 1] + } + val point = drawPath.pointList!![drawPath.pointList!!.size - 1] + drawPathCopy!!.pointList!!.add(point) + if (drawPath.pointList!!.size == 1) { + mCurrentPaths.removeAt(mCurrentPaths.size - 1) + } else { + drawPath.pointList!!.remove(point) + } + } else if ((drawPath.style == CanvasStyle.WATER_LINE || drawPath.style == CanvasStyle.GREENLAND_LINE || drawPath.style == CanvasStyle.PARKING_LINE) + && !drawPath.isOver + ) { + val drawPathCopy: DrawPath? + if (mDeletePaths!!.size == 0 || mDeletePaths[mDeletePaths.size - 1]!!.style != drawPath.style || mDeletePaths[mDeletePaths.size - 1]!!.isOver) { + drawPathCopy = DrawPath( + null, + drawPath.path, + drawPath.width, + drawPath.color, + drawPath.style + ) + drawPathCopy.rect = drawPath.rect + drawPathCopy.isOver = false + mDeletePaths.add(drawPathCopy) + } else { + drawPathCopy = mDeletePaths[mDeletePaths.size - 1] + } + val point = drawPath.pointList!![drawPath.pointList!!.size - 2] + drawPathCopy!!.pointList!!.add(point) + if (drawPath.pointList!!.size < 3) { + mCurrentPaths.removeAt(mCurrentPaths.size - 1) + } else { + drawPath.pointList!!.removeAt(drawPath.pointList!!.size - 1) + drawPath.pointList!!.remove(point) + drawPath.pointList!!.add(drawPath.pointList!![0]) + } + } else { + mDeletePaths!!.add(drawPath) + mCurrentPaths.removeAt(mCurrentPaths.size - 1) + } + if (mCurrentPaths.isNotEmpty()) { + //将路径保存列表中的路径重绘在画布上 + for (dp in mCurrentPaths) { + if (dp.style == CanvasStyle.POLY_LINE) { + dp.path.reset() + for (i in dp.pointList!!.indices) { + val point = dp.pointList!![i] + mPaintCircular.color = dp.color + if (i == 0) { + mCanvas!!.drawCircle( + point.x.toFloat(), + point.y.toFloat(), + 2f, + mPaintCircular + ) + dp.path.moveTo(point.x.toFloat(), point.y.toFloat()) + } else { + dp.path.lineTo(point.x.toFloat(), point.y.toFloat()) + } + } + mCanvas!!.drawPath(dp.path, dp.getPaint(mPaint)!!) + } else if (dp.style == CanvasStyle.RAILWAY_LINE) { + dp.path.reset() + for (i in dp.pointList!!.indices) { + val point = dp.pointList!![i] + if (i == 0) { + mCanvas!!.drawCircle( + point.x.toFloat(), + point.y.toFloat(), + 2f, + mPaintCircular + ) + dp.path.moveTo(point.x.toFloat(), point.y.toFloat()) + } else { + dp.path.lineTo(point.x.toFloat(), point.y.toFloat()) + } + } + mCanvas!!.drawPath(dp.path, mPaintRailway1) + mCanvas!!.drawPath(dp.path, mPaintRailway2) + } else if (dp.style == CanvasStyle.GREENLAND_LINE) { + dp.path.reset() + for (i in dp.pointList!!.indices) { + val point = dp.pointList!![i] + if (i == 0) { + mCanvas!!.drawCircle( + point.x.toFloat(), + point.y.toFloat(), + 2f, + mPaintCircular + ) + dp.path.moveTo(point.x.toFloat(), point.y.toFloat()) + } else { + dp.path.lineTo(point.x.toFloat(), point.y.toFloat()) + } + } + mCanvas!!.drawPath(dp.path, mPaintGreenland) + mCanvas!!.drawPath(dp.path, mPaintGreenland1) + } else if (dp.style == CanvasStyle.WATER_LINE) { + dp.path.reset() + for (i in dp.pointList!!.indices) { + val point = dp.pointList!![i] + if (i == 0) { + mCanvas!!.drawCircle( + point.x.toFloat(), + point.y.toFloat(), + 2f, + mPaintCircular + ) + dp.path.moveTo(point.x.toFloat(), point.y.toFloat()) + } else { + dp.path.lineTo(point.x.toFloat(), point.y.toFloat()) + } + } + mCanvas!!.drawPath(dp.path, mPaintWater) + mCanvas!!.drawPath(dp.path, mPaintWater1) + } else if (dp.style == CanvasStyle.PARKING_LINE) { + dp.path.reset() + for (i in dp.pointList!!.indices) { + val point = dp.pointList!![i] + if (i == 0) { + mCanvas!!.drawCircle( + point.x.toFloat(), + point.y.toFloat(), + 2f, + mPaintCircular + ) + dp.path.moveTo(point.x.toFloat(), point.y.toFloat()) + } else { + dp.path.lineTo(point.x.toFloat(), point.y.toFloat()) + } + } + mCanvas!!.drawPath(dp.path, mPaintParking) + mCanvas!!.drawPath(dp.path, mPaintParking1) + } else if (dp.style == CanvasStyle.CIRCULAR_POINT) { + mPaintCircular.color = dp.color + mCanvas!!.drawCircle( + dp.pointList!![0].x.toFloat(), + dp.pointList!![0].y.toFloat(), + dp.width.toFloat(), + mPaintCircular + ) + } else { + mCanvas!!.drawPath(dp.path, dp.getPaint(mPaint)!!) + } + } + } + invalidate() // 刷新 + } + if (mCurrentPaths.size == 0) { + mDrawPath = null + } + return mCurrentPaths.size != 0 + } + + /** + * 恢复撤销的上一步 + */ + fun forward() { + if (mDeletePaths!!.size > 0) { + //将删除的路径列表中的最后一个,也就是最顶端路径取出(栈),并加入路径保存列表中 + val dp = mDeletePaths[mDeletePaths.size - 1] + if ((dp!!.style == CanvasStyle.POLY_LINE + || dp.style == CanvasStyle.RAILWAY_LINE) + && !dp.isOver + ) { + val dp2: DrawPath? + if (mCurrentPaths.size > 0 && mCurrentPaths[mCurrentPaths.size - 1].style == dp.style && !mCurrentPaths[mCurrentPaths.size - 1].isOver) { + dp2 = mCurrentPaths[mCurrentPaths.size - 1] + } else { + dp2 = DrawPath(null, dp.path, dp.width, dp.color, dp.style) + dp2.isOver = false + dp2.rect = dp.rect + mCurrentPaths.add(dp2) + if (mListener != null) { + mListener!!.onDraw() + } + } + val point = dp.pointList!![dp.pointList!!.size - 1] + dp2.pointList!!.add(point) + dp.pointList!!.remove(point) + } else if ((dp.style == CanvasStyle.WATER_LINE || dp.style == CanvasStyle.GREENLAND_LINE || dp.style == CanvasStyle.PARKING_LINE) + && !dp.isOver + ) { + val dp2: DrawPath? + if (mCurrentPaths.size > 0 && mCurrentPaths[mCurrentPaths.size - 1].style == dp.style && !mCurrentPaths[mCurrentPaths.size - 1].isOver) { + dp2 = mCurrentPaths[mCurrentPaths.size - 1] + } else { + dp2 = DrawPath(null, dp.path, dp.width, dp.color, dp.style) + dp2.isOver = false + dp2.rect = dp.rect + mCurrentPaths.add(dp2) + if (mListener != null) { + mListener!!.onDraw() + } + } + val point = dp.pointList!![dp.pointList!!.size - 1] + if (dp2.pointList!!.size > 1) { + dp2.pointList!!.removeAt(dp2.pointList!!.size - 1) + } + dp2.pointList!!.add(point) + dp2.pointList!!.add(dp2.pointList!![0]) + dp.pointList!!.remove(point) + } else { + mCurrentPaths.add(dp) + if (mListener != null) { + mListener!!.onDraw() + } + } + //将取出的路径重绘在画布上 + if (dp.style == CanvasStyle.POLY_LINE) { + val dp2 = mCurrentPaths[mCurrentPaths.size - 1] + dp2.path.reset() + if (dp2.pointList != null && dp2.pointList!!.size > 0) { + for (i in dp2.pointList!!.indices) { + val point = dp2.pointList!![i] + mPaintCircular.color = dp2.color + if (i == 0) { + mCanvas!!.drawCircle( + point.x.toFloat(), + point.y.toFloat(), + 2f, + mPaintCircular + ) + dp2.path.moveTo(point.x.toFloat(), point.y.toFloat()) + } else { + dp2.path.lineTo(point.x.toFloat(), point.y.toFloat()) + } + } + } + mCanvas!!.drawPath(dp2.path, dp2.getPaint(mPaint)!!) + } else if (dp.style == CanvasStyle.RAILWAY_LINE) { + val dp2 = mCurrentPaths[mCurrentPaths.size - 1] + dp2.path.reset() + if (dp2.pointList != null && dp2.pointList!!.size > 0) { + for (i in dp2.pointList!!.indices) { + val point = dp2.pointList!![i] + if (i == 0) { + dp2.path.moveTo(point.x.toFloat(), point.y.toFloat()) + } else { + dp2.path.lineTo(point.x.toFloat(), point.y.toFloat()) + } + } + } + mCanvas!!.drawPath(dp2.path, mPaintRailway1) + mCanvas!!.drawPath(dp2.path, mPaintRailway2) + } else if (dp.style == CanvasStyle.GREENLAND_LINE) { + val dp2 = mCurrentPaths[mCurrentPaths.size - 1] + initCanvas() + dp2.path.reset() + if (dp2.pointList != null && dp2.pointList!!.size > 0) { + for (i in dp2.pointList!!.indices) { + val point = dp2.pointList!![i] + if (i == 0) { + mCanvas!!.drawCircle( + point.x.toFloat(), + point.y.toFloat(), + 2f, + mPaintCircular + ) + dp2.path.moveTo(point.x.toFloat(), point.y.toFloat()) + } else { + dp2.path.lineTo(point.x.toFloat(), point.y.toFloat()) + } + } + } + mCanvas!!.drawPath(dp2.path, mPaintGreenland) + mCanvas!!.drawPath(dp2.path, mPaintGreenland1) + } else if (dp.style == CanvasStyle.WATER_LINE) { + val dp2 = mCurrentPaths[mCurrentPaths.size - 1] + initCanvas() + dp2.path.reset() + if (dp2.pointList != null && dp2.pointList!!.size > 0) { + for (i in dp2.pointList!!.indices) { + val point = dp2.pointList!![i] + if (i == 0) { + mCanvas!!.drawCircle( + point.x.toFloat(), + point.y.toFloat(), + 2f, + mPaintCircular + ) + dp2.path.moveTo(point.x.toFloat(), point.y.toFloat()) + } else { + dp2.path.lineTo(point.x.toFloat(), point.y.toFloat()) + } + } + } + mCanvas!!.drawPath(dp2.path, mPaintWater) + mCanvas!!.drawPath(dp2.path, mPaintWater1) + } else if (dp.style == CanvasStyle.PARKING_LINE) { + val dp2 = mCurrentPaths[mCurrentPaths.size - 1] + initCanvas() + dp2!!.path.reset() + if (dp2.pointList != null && dp2.pointList!!.size > 0) { + for (i in dp2.pointList!!.indices) { + val point = dp2.pointList!![i] + if (i == 0) { + mCanvas!!.drawCircle( + point.x.toFloat(), + point.y.toFloat(), + 2f, + mPaintCircular + ) + dp2.path.moveTo(point.x.toFloat(), point.y.toFloat()) + } else { + dp2.path.lineTo(point.x.toFloat(), point.y.toFloat()) + } + } + } + mCanvas!!.drawPath(dp2.path, mPaintParking) + mCanvas!!.drawPath(dp2.path, mPaintParking1) + } else if (dp.style == CanvasStyle.CIRCULAR_POINT) { + mPaintCircular.color = dp.color + mCanvas!!.drawCircle( + dp.pointList!![0].x.toFloat(), + dp.pointList!![0].y.toFloat(), + dp.width.toFloat(), + mPaintCircular + ) + } else { + mCanvas!!.drawPath(dp.path, dp.getPaint(mPaint)!!) + } + //将该路径从删除的路径列表中去除 + if ((dp.style == CanvasStyle.POLY_LINE + || dp.style == CanvasStyle.RAILWAY_LINE) + && !dp.isOver + ) { + if (dp.pointList!!.size == 0) { + mDeletePaths.remove(dp) + } + } else if ((dp.style == CanvasStyle.WATER_LINE || dp.style == CanvasStyle.GREENLAND_LINE || dp.style == CanvasStyle.PARKING_LINE) + && !dp.isOver + ) { + if (dp.pointList!!.size == 0) { + mDeletePaths.remove(dp) + } + } else { + mDeletePaths.removeAt(mDeletePaths.size - 1) + } + invalidate() + } + } + + /* + * 清空的主要思想就是初始化画布 + * 将保存路径的两个List清空 + * */ + fun removeAllPaint() { + //调用初始化画布函数以清空画布 + initCanvas() + invalidate() //刷新 + mPath = null + mDrawPath = null + mCurrentPaths.clear() + mDeletePaths!!.clear() + } + + /** + * 设置画笔粗细 + * + * @param paintWidth + */ + fun setPaintWidth(paintWidth: Int) { + mPaintWidth = paintWidth + if (mPaint != null) { + mPaint.strokeWidth = mPaintWidth.toFloat() + } + } + + /** + * 设置画笔颜色 + * + * @param color + */ + fun setPaintColor(color: Int) { + mPaintColor = color + if (mPaint != null) { + mPaint.color = mPaintColor + } + } + + /** + * 将图形数据绘制在画布上 + * + * @param value + */ + fun setDrawPathList(value: MutableList) { + mPath = null + mCurrentPaths = value + if (mListener != null) { + mListener!!.onDraw() + } + mDeletePaths!!.clear() + if (mCanvas != null) { + if (mCurrentPaths.size > 0) { + for (dp in mCurrentPaths) { + if (dp.style == CanvasStyle.RAILWAY_LINE) { + dp.path.reset() + for (i in dp.pointList!!.indices) { + if (i == 0) { + dp.path.moveTo( + dp.pointList!![i].x.toFloat(), + dp.pointList!![i].y.toFloat() + ) + } else { + dp.path.lineTo( + dp.pointList!![i].x.toFloat(), + dp.pointList!![i].y.toFloat() + ) + } + } + mCanvas!!.drawPath(dp.path, mPaintRailway1) + mCanvas!!.drawPath(dp.path, mPaintRailway2) + } else if (dp.style == CanvasStyle.GREENLAND_LINE) { + mCanvas!!.drawPath(dp.path, mPaintGreenland) + mCanvas!!.drawPath(dp.path, mPaintGreenland1) + } else if (dp.style == CanvasStyle.WATER_LINE) { + mCanvas!!.drawPath(dp.path, mPaintWater) + mCanvas!!.drawPath(dp.path, mPaintWater1) + } else if (dp.style == CanvasStyle.PARKING_LINE) { + mCanvas!!.drawPath(dp.path, mPaintParking) + mCanvas!!.drawPath(dp.path, mPaintParking1) + } else if (dp.style == CanvasStyle.CIRCULAR_POINT) { + mPaintCircular.color = dp.color + mCanvas!!.drawCircle( + dp.pointList!![0].x.toFloat(), + dp.pointList!![0].y.toFloat(), + dp.width.toFloat(), + mPaintCircular + ) + } else if (dp.style == CanvasStyle.POLY_LINE) { + mPaintCircular.color = dp.color + dp.path.reset() + for (i in dp.pointList!!.indices) { + if (i == 0) { + mCanvas!!.drawCircle( + dp.pointList!![i].x.toFloat(), + dp.pointList!![i].y.toFloat(), + 2f, + mPaintCircular + ) + dp.path.moveTo( + dp.pointList!![i].x.toFloat(), + dp.pointList!![i].y.toFloat() + ) + } else { + dp.path.lineTo( + dp.pointList!![i].x.toFloat(), + dp.pointList!![i].y.toFloat() + ) + } + } + mCanvas!!.drawPath(dp.path, dp.getPaint(mPaint)!!) + } else { + mCanvas!!.drawPath(dp.path, dp.getPaint(mPaint)!!) + } + canvasStyle = dp.style + } + } + mPaint!!.color = mPaintColor + } + invalidate() // 刷新 + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + canvas.drawBitmap(mBitmap!!, 0f, 0f, mBitmapPaint) //显示旧的画布 + if (mPath != null) { + // 实时的显示 + if (isMove) { + if (canvasStyle == CanvasStyle.CIRCULAR_POINT) { + mMatrixCircular.reset() + mMatrixCircular.postTranslate( + mMoveX - mStarBitmap.width / 2, + mMoveY - mCircularP + ) + canvas.drawBitmap(mStarBitmap, mMatrixCircular, null) + } else if (canvasStyle == CanvasStyle.STRAIGHT_LINE) { + if (mDrawPath != null && mDrawPath!!.pointList!!.size > 0) { + val x = mDrawPath!!.pointList!![0].x + val y = mDrawPath!!.pointList!![0].y + val Y2 = mMoveY - mCircularP + mStarBitmap.height / 2 + canvas.drawLine(x.toFloat(), y.toFloat(), mMoveX, Y2, mPaint!!) + } + mMatrixCircular.reset() + mMatrixCircular.postTranslate( + mMoveX - mStarBitmap.width / 2, + mMoveY - mCircularP + ) + canvas.drawBitmap(mStarBitmap, mMatrixCircular, null) + } else if (canvasStyle == CanvasStyle.POLY_LINE) { + if (mDrawPath != null && mDrawPath!!.pointList!!.size > 0) { + val x = mDrawPath!!.pointList!![mDrawPath!!.pointList!!.size - 1].x + val y = mDrawPath!!.pointList!![mDrawPath!!.pointList!!.size - 1].y + val Y2 = mMoveY - mCircularP + mStarBitmap.height / 2 + canvas.drawLine(x.toFloat(), y.toFloat(), mMoveX, Y2, mPaint!!) + } + mMatrixCircular.reset() + mMatrixCircular.postTranslate( + mMoveX - mStarBitmap.width / 2, + mMoveY - mCircularP + ) + canvas.drawBitmap(mStarBitmap, mMatrixCircular, null) + } else if (canvasStyle == CanvasStyle.RECT_LINE) { + if (mDownX > mMoveX && mDownY > mMoveY) { + canvas.drawRect(mMoveX, mMoveY, mDownX, mDownY, mPaint!!) + } else if (mDownX < mMoveX && mDownY > mMoveY) { + canvas.drawRect(mDownX, mMoveY, mMoveX, mDownY, mPaint!!) + } else if (mDownX > mMoveX && mDownY < mMoveY) { + canvas.drawRect(mMoveX, mDownY, mDownX, mMoveY, mPaint!!) + } else { + canvas.drawRect(mDownX, mDownY, mMoveX, mMoveY, mPaint!!) + } + } else if (canvasStyle == CanvasStyle.ELLIPSE_LINE) { + if (mDownX > mMoveX && mDownY > mMoveY) { + canvas.drawOval(RectF(mMoveX, mMoveY, mDownX, mDownY), mPaint!!) + } else if (mDownX < mMoveX && mDownY > mMoveY) { + canvas.drawOval(RectF(mDownX, mMoveY, mMoveX, mDownY), mPaint!!) + } else if (mDownX > mMoveX && mDownY < mMoveY) { + canvas.drawOval(RectF(mMoveX, mDownY, mDownX, mMoveY), mPaint!!) + } else { + canvas.drawOval(RectF(mDownX, mDownY, mMoveX, mMoveY), mPaint!!) + } + } else { + if (canvasStyle == CanvasStyle.RAILWAY_LINE) { + canvas.drawPath(mPath!!, mPaintRailway1) + canvas.drawPath(mPath!!, mPaintRailway2) + } else if (canvasStyle == CanvasStyle.GREENLAND_LINE) { + canvas.drawPath(mPath!!, mPaintGreenland1) + } else if (canvasStyle == CanvasStyle.WATER_LINE) { + canvas.drawPath(mPath!!, mPaintWater1) + } else if (canvasStyle == CanvasStyle.PARKING_LINE) { + canvas.drawPath(mPath!!, mPaintParking1) + } else { + canvas.drawPath(mPath!!, mPaint!!) + } + } + } else { + + +// if (mStyle == CanvasStyle.RAILWAY_LINE) { +// canvas.drawPath(mPath, mPaintRailway1); +// canvas.drawPath(mPath, mPaintRailway2); +// } else { +// canvas.drawPath(mPath, mPaint); +// } + } + } + } + + override fun onTouchEvent(event: MotionEvent): Boolean { + val x = event.x + val y = event.y + when (event.action) { + MotionEvent.ACTION_DOWN -> if (isEraser) { + clearLine(x.toInt(), y.toInt()) + } else { +// if (mCurrentPaths != null && mCurrentPaths.size() > 0) { +// for (DrawPath dp : mCurrentPaths) { +// if (dp.style == CanvasStyle.GREENLAND_LINE || dp.style == CanvasStyle.WATER_LINE) { +// return true; +// } +// } +// } + isMove = false + if (canvasStyle == CanvasStyle.RAILWAY_LINE || canvasStyle == CanvasStyle.GREENLAND_LINE || canvasStyle == CanvasStyle.WATER_LINE || canvasStyle == CanvasStyle.PARKING_LINE) { + touch_start_poly(x.toInt(), y.toInt()) + return true + } else if (canvasStyle == CanvasStyle.CIRCULAR_POINT) { + mPath = Path() + mDrawPath = DrawPath(null, mPath!!, mPaintWidth + 5, mPaintColor, canvasStyle) + return true + } else if (canvasStyle == CanvasStyle.POLY_LINE) { + if (mDeletePaths != null && mDeletePaths.size > 0) { + mDeletePaths.clear() + } + if (mDrawPath != null && mDrawPath!!.style == CanvasStyle.POLY_LINE && !mDrawPath!!.isOver) { + return true + } + mPath = Path() + mDrawPath = DrawPath( + Point(x.toInt(), y.toInt()), + mPath!!, + mPaintWidth, + mPaintColor, + canvasStyle + ) + mDrawPath!!.isOver = false + return true + } else if (canvasStyle == CanvasStyle.STRAIGHT_LINE) { + if (mDeletePaths != null && mDeletePaths.size > 0) { + mDeletePaths.clear() + } + if (mDrawPath != null && mDrawPath!!.style == CanvasStyle.STRAIGHT_LINE && !mDrawPath!!.isOver) { + return true + } + mPath = Path() + mDrawPath = DrawPath( + Point(x.toInt(), y.toInt()), + mPath!!, + mPaintWidth, + mPaintColor, + canvasStyle + ) + mDrawPath!!.isOver = false + return true + } + mPath = Path() + mDrawPath = DrawPath( + Point(x.toInt(), y.toInt()), + mPath!!, + mPaintWidth, + mPaintColor, + canvasStyle + ) + touch_start(x, y) + } + MotionEvent.ACTION_MOVE -> { + if (isEraser) { + return true + } + if (canvasStyle == CanvasStyle.RAILWAY_LINE || canvasStyle == CanvasStyle.GREENLAND_LINE || canvasStyle == CanvasStyle.WATER_LINE || canvasStyle == CanvasStyle.PARKING_LINE) return true + +// if (mCurrentPaths != null && mCurrentPaths.size() > 0) { +// for (DrawPath dp : mCurrentPaths) { +// if (dp.style == CanvasStyle.GREENLAND_LINE || dp.style == CanvasStyle.WATER_LINE) { +// return true; +// } +// } +// } + isMove = true + if (x == mDownX && y == mDownY) return false + if (canvasStyle == CanvasStyle.POLY_LINE || canvasStyle == CanvasStyle.STRAIGHT_LINE || canvasStyle == CanvasStyle.RECT_LINE || canvasStyle == CanvasStyle.ELLIPSE_LINE || canvasStyle == CanvasStyle.CIRCULAR_POINT) { + touch_move(x, y) + } else { + if (contains( + mDownX.toInt(), + mDownY.toInt(), + x.toInt(), + y.toInt(), + ChouXiBanJing + ) + ) { + return true + } + touch_move_line(x, y) + } + invalidate() + } + MotionEvent.ACTION_UP -> { + if (isEraser) { + return true + } + if (canvasStyle == CanvasStyle.RAILWAY_LINE || canvasStyle == CanvasStyle.GREENLAND_LINE || canvasStyle == CanvasStyle.WATER_LINE || canvasStyle == CanvasStyle.PARKING_LINE) return true + // if (mCurrentPaths != null && mCurrentPaths.size() > 0) { +// for (DrawPath dp : mCurrentPaths) { +// if (dp.style == CanvasStyle.GREENLAND_LINE || dp.style == CanvasStyle.WATER_LINE) { +// return true; +// } +// } +// } + touch_up(x, y) + invalidate() + isMove = false + } + } + return true + } + + /** + * 橡皮擦捕捉清除 + * + * @param x + * @param y + */ + private fun clearLine(x: Int, y: Int) { + if (mCurrentPaths.size == 0) return + val rect = Rect(x - EraserWight, y - EraserWight, x + EraserWight, y + EraserWight) + for (i in mCurrentPaths.size - 1 downTo -1 + 1) { + val path = mCurrentPaths[i] + if (path.rect != null && path.rect!!.intersects( + rect.left, + rect.top, + rect.right, + rect.bottom + ) + ) { + if (LineIntersectRect(path.pointList, rect)) { + initCanvas() + mDeletePaths!!.add(path) + mCurrentPaths.remove(path) + for (dp in mCurrentPaths) { + if (dp.style == CanvasStyle.RAILWAY_LINE) { + dp.path.reset() + if (dp.pointList != null && dp.pointList!!.size > 0) { + for (k in dp.pointList!!.indices) { + if (k == 0) { + dp.path.moveTo( + dp.pointList!![k].x.toFloat(), + dp.pointList!![k].y.toFloat() + ) + } else { + dp.path.lineTo( + dp.pointList!![k].x.toFloat(), + dp.pointList!![k].y.toFloat() + ) + } + } + } + mCanvas!!.drawPath(dp.path, mPaintRailway1) + mCanvas!!.drawPath(dp.path, mPaintRailway2) + } else if (dp.style == CanvasStyle.GREENLAND_LINE) { + mCanvas!!.drawPath(dp.path, mPaintGreenland) + mCanvas!!.drawPath(dp.path, mPaintGreenland1) + } else if (dp.style == CanvasStyle.WATER_LINE) { + mCanvas!!.drawPath(dp.path, mPaintWater) + mCanvas!!.drawPath(dp.path, mPaintWater1) + } else if (dp.style == CanvasStyle.PARKING_LINE) { + mCanvas!!.drawPath(dp.path, mPaintParking) + mCanvas!!.drawPath(dp.path, mPaintParking1) + } else if (dp.style == CanvasStyle.CIRCULAR_POINT) { + mPaintCircular.color = dp.color + mCanvas!!.drawCircle( + dp.pointList!![0].x.toFloat(), + dp.pointList!![0].y.toFloat(), + dp.width.toFloat(), + mPaintCircular + ) + } else if (dp.style == CanvasStyle.POLY_LINE) { + mPaintCircular.color = dp.color + dp.path.reset() + if (dp.pointList != null && dp.pointList!!.size > 0) { + for (k in dp.pointList!!.indices) { + if (k == 0) { + mCanvas!!.drawCircle( + dp.pointList!![k].x.toFloat(), + dp.pointList!![k].y.toFloat(), + 2f, + mPaintCircular + ) + dp.path.moveTo( + dp.pointList!![k].x.toFloat(), + dp.pointList!![k].y.toFloat() + ) + } else { + dp.path.lineTo( + dp.pointList!![k].x.toFloat(), + dp.pointList!![k].y.toFloat() + ) + } + } + } + mCanvas!!.drawPath(dp.path, dp.getPaint(mPaint)!!) + } else { + mCanvas!!.drawPath(dp.path, dp.getPaint(mPaint)!!) + } + } + invalidate() // 刷新 + return + } + } + } + invalidate() + } + + /** + * 整条线段是否穿过矩形 + * + * @param pointList + * @param rect + * @return + */ + private fun LineIntersectRect(pointList: List?, rect: Rect?): Boolean { + if (pointList != null && pointList.size > 1 && rect != null && !rect.isEmpty) { + for (i in 0 until pointList.size - 1) { + if (CheckRectLine(pointList[i], pointList[i + 1], rect)) return true + } + } else if (pointList != null && pointList.size == 1) { + val point = pointList[0] + if (point.x >= rect!!.left && point.x <= rect.right && point.y >= rect.top && point.y <= rect.bottom) { + return true + } + } + return false + } + + /** + * 获取画布上的图形数据 + * + * @return + */ + val paths: List? + get() { + setPolyLineOver() + if (mCurrentPaths.size > 0) { + var i = 0 + while (i < mCurrentPaths.size) { + val drawPath = mCurrentPaths[i] + if (drawPath.style == CanvasStyle.POLY_LINE + || drawPath.style == CanvasStyle.RAILWAY_LINE + ) { + if (drawPath.pointList!!.size < 2) { + mCurrentPaths.remove(drawPath) + i-- + } + } else if (drawPath.style == CanvasStyle.WATER_LINE || drawPath.style == CanvasStyle.GREENLAND_LINE || drawPath.style == CanvasStyle.PARKING_LINE) { + if (drawPath.pointList!!.size < 4) { + mCurrentPaths.remove(drawPath) + i-- + } + } + i++ + } + } + return mCurrentPaths + } + + /** + * 得到缩略图 + * + * @return + */ + val thumbnail: Bitmap? + get() { + if (mCurrentPaths == null || mCurrentPaths!!.size == 0) { + return null + } + val whiteBgBitmap = Bitmap.createBitmap( + mBitmap!!.width, + mBitmap!!.height, + Bitmap.Config.ARGB_8888 + ) + val canvas = Canvas(whiteBgBitmap) + canvas.drawColor(Color.WHITE) + canvas.drawBitmap(mBitmap!!, 0f, 0f, null) + return ThumbnailUtils.extractThumbnail(whiteBgBitmap, 100, 100) + } + + /** + * 设置是否保存中间点信息 + * + * @param b + */ + fun setIsSavePoint(b: Boolean) { + isSavePoint = b + } + + /** + * 设置橡皮擦按钮是否开启或关闭 + * + * @param b + */ + fun setEraser(b: Boolean) { + isEraser = b + if (b) { + setPolyLineOver() + } + } + + /** + * 判断线与垂直线相交 + * + * @param startX + * @param startY + * @param endX + * @param endY + * @param x0 + * @param y1 + * @param y2 + * @return + */ + private fun CheckRectLineV( + startX: Float, + startY: Float, + endX: Float, + endY: Float, + x0: Float, + y1: Float, + y2: Float + ): Boolean { + if (x0 < startX && x0 < endX) return false + if (x0 > startX && x0 > endX) return false + if (startX == endX) { + return if (x0 == startX) { + if (startY < y1 && endY < y1) return false + !(startY > y2 && endY > y2) + } else { + false + } + } + val y = (endY - startY) * (x0 - startX) / (endX - startX) + startY + return y in y1..y2 + } + + /** + * 判断线与水平线相交 + * + * @param startX + * @param startY + * @param endX + * @param endY + * @param y0 + * @param x1 + * @param x2 + * @return + */ + private fun CheckRectLineH( + startX: Float, + startY: Float, + endX: Float, + endY: Float, + y0: Float, + x1: Float, + x2: Float + ): Boolean { + //直线在点的上方 + if (y0 < startY && y0 < endY) return false + //直线在点的下方 + if (y0 > startY && y0 > endY) return false + //水平直线 + if (startY == endY) { + //水平直线与点处于同一水平。 + return if (y0 == startY) { + //直线在点的左边 + if (startX < x1 && endX < x1) return false + //直线在x2垂直线右边 + !(startX > x2 && endX > x2) + //直线的部分或者全部处于点与x2垂直线之间 + } else //水平直线与点不处于同一水平。 + { + false + } + } + //斜线 + val x = (endX - startX) * (y0 - startY) / (endY - startY) + startX + return x in x1..x2 + } + + /** + * 直线是否穿过矩形 + * + * @param start + * @param end + * @param rect + * @return + */ + private fun CheckRectLine(start: Point, end: Point, rect: Rect): Boolean { + var result = false + if (rect.contains(start.x, start.y) || rect.contains(end.x, end.y)) result = true else { + if (CheckRectLineH( + start.x.toFloat(), + start.y.toFloat(), + end.x.toFloat(), + end.y.toFloat(), + rect.top.toFloat(), + rect.left.toFloat(), + rect.right.toFloat() + ) + ) return true + if (CheckRectLineH( + start.x.toFloat(), + start.y.toFloat(), + end.x.toFloat(), + end.y.toFloat(), + rect.bottom.toFloat(), + rect.left.toFloat(), + rect.right.toFloat() + ) + ) return true + if (CheckRectLineV( + start.x.toFloat(), + start.y.toFloat(), + end.x.toFloat(), + end.y.toFloat(), + rect.left.toFloat(), + rect.top.toFloat(), + rect.bottom.toFloat() + ) + ) return true + if (CheckRectLineV( + start.x.toFloat(), + start.y.toFloat(), + end.x.toFloat(), + end.y.toFloat(), + rect.right.toFloat(), + rect.top.toFloat(), + rect.bottom.toFloat() + ) + ) return true + } + return result + } + + /** + * 两个矩形是否包含 + * + * @param x1 + * @param y1 + * @param x2 + * @param y2 + * @param dis + * @return + */ + private fun contains(x1: Int, y1: Int, x2: Int, y2: Int, dis: Int): Boolean { + val rect = Rect(x1 - dis, y1 - dis, x1 + dis, y1 + dis) + return rect.contains(x2, y2) + } + + companion object { + /* + 橡皮擦捕捉半径 + */ + private const val EraserWight = 12 + + /** + * 线点 抽稀半径 + */ + private const val ChouXiBanJing = 12 //抽稀半径 + + /** + * 手指滑动的距离,两点之间像素值少于4 的点不要 + */ + private const val TOUCH_TOLERANCE = 4f + } +} \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/omqs/ui/fragment/note/CanvasViewHelper.kt b/app/src/main/java/com/navinfo/omqs/ui/fragment/note/CanvasViewHelper.kt new file mode 100644 index 00000000..fc0e1805 --- /dev/null +++ b/app/src/main/java/com/navinfo/omqs/ui/fragment/note/CanvasViewHelper.kt @@ -0,0 +1,424 @@ +package com.navinfo.omqs.ui.fragment.note + +import android.graphics.Path +import android.graphics.Point +import android.graphics.Rect +import android.graphics.RectF +import android.text.TextUtils +import com.navinfo.collect.library.data.entity.NoteBean +import com.navinfo.collect.library.data.entity.SketchAttachContent +import com.navinfo.collect.library.map.NIMapController +import com.navinfo.collect.library.utils.GeometryTools +import com.navinfo.omqs.ui.fragment.note.CanvasView.CanvasStyle +import io.realm.RealmList +import org.locationtech.jts.geom.Coordinate +import org.oscim.backend.canvas.Color +import org.oscim.core.GeoPoint +import java.util.UUID +import kotlin.math.abs +import kotlin.math.cos +import kotlin.math.sin + +/** + * @author zhjch + * @version V1.0 + * @ClassName: CanvasViewHelper + * @Date 2016/5/16 + * @Description: ${TODO}(用一句话描述该文件做什么) + */ +object CanvasViewHelper { + private const val mD2I = 3600000 + fun createNoteBean( + controller: NIMapController, + mCurrentPaths: List, + ): NoteBean { + val noteBean = NoteBean(UUID.randomUUID().toString()) + if (mCurrentPaths.isNotEmpty()) { + val list: RealmList = RealmList() + noteBean.list = list + for (index in mCurrentPaths.indices) { + val dp: CanvasView.DrawPath = mCurrentPaths[index] + val geo = SketchAttachContent(UUID.randomUUID().toString()) + val pointList = dp.pointList ?: continue + if (dp.style === CanvasStyle.GREENLAND_LINE || dp.style === CanvasStyle.WATER_LINE || dp.style === CanvasStyle.PARKING_LINE) { + val geoPointList = mutableListOf() + for (i in pointList.indices) { + val point = pointList[i] + val geoPoint: GeoPoint = controller.viewportHandler.fromScreenPoint( + point + ) + geoPointList.add(geoPoint) + if (index == 0 && i == 0) { + noteBean.guideGeometry = + GeometryTools.createGeometry(geoPoint).toText() + } + } + geo.style = createLineStyle(dp.style, dp.width, dp.color) + geo.geometry = GeometryTools.createPolygon(geoPointList).toText() + } else if (dp.style === CanvasStyle.CIRCULAR_POINT) { + val point = pointList[0] + val geoPoint: GeoPoint = controller.viewportHandler.fromScreenPoint(point) + geo.style = createLineStyle(dp.style, dp.width, dp.color) + geo.geometry = GeometryTools.createGeometry(geoPoint).toText() + noteBean.guideGeometry = geo.geometry + } else if (dp.style === CanvasStyle.ELLIPSE_LINE) { + dp.rect?.let { + val pointLT = Point(it.left, it.top) + val pointRB = Point(it.right, it.bottom) + val geoPointLT: GeoPoint = + controller.viewportHandler.fromScreenPoint(pointLT) + val geoPointRB: GeoPoint = + controller.viewportHandler.fromScreenPoint(pointRB) + val minX: Double + val maxX: Double + val minY: Double + val maxY: Double + if (geoPointLT.longitude < geoPointRB.longitude) { + minX = (geoPointLT.longitude * mD2I) + maxX = (geoPointRB.longitude * mD2I) + } else { + minX = (geoPointRB.longitude * mD2I) + maxX = (geoPointLT.longitude * mD2I) + } + if (geoPointLT.latitude < geoPointRB.latitude) { + minY = (geoPointLT.latitude * mD2I) + maxY = (geoPointRB.latitude * mD2I) + } else { + minY = (geoPointRB.latitude * mD2I) + maxY = (geoPointLT.latitude * mD2I) + } + val xR = (maxX - minX) / 2 + val yR = (maxY - minY) / 2 + var a = 0.0 + var tempX = xR * cos(a) + xR + minX + val tempY = yR * sin(a) + yR + minY + val firstX = tempX + val geoPointList = mutableListOf() + geoPointList.add(GeoPoint(tempX / mD2I, tempY / mD2I)) + var bLeft = false + var bRight = false + var zeng = 0.1 + if (controller.mMapView.mapLevel >= 20) { + zeng = 0.2 + } + while (!bLeft || !bRight) { + a += zeng + val x1 = (xR * cos(a) + xR + minX).toInt().toDouble() + val y1 = (yR * sin(a) + yR + minY).toInt().toDouble() + if (!bLeft && x1 > tempX) { + bLeft = true + } + if (!bRight && bLeft && x1 <= tempX) { + bRight = true + geoPointList.add( + GeoPoint( + firstX / mD2I, + tempY / mD2I + ) + ) + } else { + tempX = x1 + geoPointList.add(GeoPoint(x1 / mD2I, y1 / mD2I)) + } + } + if (index == 0) { + noteBean.guideGeometry = + GeometryTools.createGeometry(geoPointList[0]).toText() + } + geo.style = createLineStyle(dp.style, dp.width, dp.color) + geo.geometry = GeometryTools.createLineString(geoPointList).toText() + } + } else { + val geoPointList = mutableListOf() + for (i in pointList.indices) { + val point = pointList[i] + val geoPoint: GeoPoint = + controller.viewportHandler.fromScreenPoint(point) + geoPointList.add(geoPoint) + if (index == 0 && i == 0) { + noteBean.guideGeometry = + GeometryTools.createGeometry(geoPoint).toText() + } + } + geo.style = createLineStyle(dp.style, dp.width, dp.color) + geo.geometry = GeometryTools.createLineString(geoPointList).toText() + } + list.add(geo) + } + } + return noteBean + } + + fun createDrawPaths( + controller: NIMapController, + att: NoteBean + ): MutableList { + val contents: List = att.list + val drawPaths: MutableList = mutableListOf() + var width = 5 + var canvasStyle = CanvasStyle.FREE_LINE + var color = Color.BLACK + for (geo in contents) { + var max_x = 0 + var max_y = 0 + var min_x = 0 + var min_y = 0 + val style = geo.style + if (!TextUtils.isEmpty(style) && style.length > 3) { + try { + if (style.startsWith("4")) { + canvasStyle = CanvasStyle.RAILWAY_LINE + } else if (style.startsWith("5")) { + if (style.contains("cde3ac")) { + canvasStyle = CanvasStyle.GREENLAND_LINE + } else if (style.contains("abcaff")) { + canvasStyle = CanvasStyle.WATER_LINE + } else if (style.contains("fffe98")) { + canvasStyle = CanvasStyle.PARKING_LINE + } + } else { + val s = style.substring(0, 1) + if (TextUtils.equals(s, "2")) { + canvasStyle = CanvasStyle.STRAIGHT_LINE + } else if (TextUtils.equals(s, "3")) { + canvasStyle = CanvasStyle.RECT_LINE + } else if (TextUtils.equals(s, "6")) { + canvasStyle = CanvasStyle.POLY_LINE + } else if (TextUtils.equals(s, "7")) { + canvasStyle = CanvasStyle.ELLIPSE_LINE + } else if (TextUtils.equals(s, "9")) { + canvasStyle = CanvasStyle.CIRCULAR_POINT + } else if (TextUtils.equals(s, "1")) { + canvasStyle = CanvasStyle.FREE_LINE + } + width = style.substring(1, 3).toInt() + var colorStr = style.substring(3, style.length) + if (colorStr.length == 6) { + colorStr = "ff$colorStr" + } else if (colorStr.length == 8) { + } else { + colorStr = "ff000000" + } + color = colorStr.toLong(16).toInt() + } + } catch (e: Exception) { + e.printStackTrace() + } + val path = Path() + val pointList: MutableList = ArrayList() + if (canvasStyle === CanvasStyle.GREENLAND_LINE || canvasStyle === CanvasStyle.WATER_LINE || canvasStyle === CanvasStyle.PARKING_LINE) { +// val polygonGeometry: PolygonGeometry = geo.geo as PolygonGeometry +// if (polygonGeometry != null) { +// val xyz: Array> = polygonGeometry.getCoordinates() +// if (xyz != null && xyz.isNotEmpty() && xyz[0].size > 1) { +// var geoPoint: GeoPoint? = GeoPoint(xyz[0][0][0], xyz[0][0][1]) +// val movePoint: Point = .geoToScreen(geoPoint) +// max_x = movePoint.x +// max_y = movePoint.y +// min_x = movePoint.x +// min_y = movePoint.y +// path.reset() +// path.moveTo(movePoint.x.toFloat(), movePoint.y.toFloat()) +// pointList.add(Point(movePoint.x, movePoint.y)) +// for (i in 1 until xyz[0].size) { +// val x_y = xyz[0][i] +// if (x_y != null) { +// geoPoint = GeoPoint(x_y[0], x_y[1]) +// val point: Point = projection.geoToScreen(geoPoint) +// if (point.x > max_x) { +// max_x = point.x +// } +// if (point.x < min_x) { +// min_x = point.x +// } +// if (point.y > max_y) { +// max_y = point.y +// } +// if (point.y < min_y) { +// min_y = point.y +// } +// path.lineTo(point.x.toFloat(), point.y.toFloat()) +// pointList.add(point) +// } +// } +// path.close() +// } +// } +// val drawPath = +// CanvasView.DrawPath(pointList[0], path, width, color, canvasStyle) +// val rect = Rect(min_x, min_y, max_x, max_y) +// drawPath.rect = rect +// drawPath.pointList = pointList +// drawPaths.add(drawPath) + } else if (canvasStyle === CanvasStyle.CIRCULAR_POINT) { +// val pointGeometry: PointGeometry = geo.geo as PointGeometry +// if (pointGeometry != null && pointGeometry.getCoordinates() != null) { +// val geoPoint: GeoPoint = GeoPoint( +// pointGeometry.getCoordinates().get(0), +// pointGeometry.getCoordinates().get(1) +// ) +// val movePoint: Point = projection.geoToScreen(geoPoint) +// pointList.add(movePoint) +// val drawPath = DrawPath(movePoint, path, width, color, canvasStyle) +// val rect = Rect( +// movePoint.x - width - 20, +// movePoint.y - width - 20, +// movePoint.x + width + 20, +// movePoint.y + width + 20 +// ) +// drawPath.rect = rect +// drawPath.pointList = pointList +// drawPaths.add(drawPath) +// } + } else if (canvasStyle === CanvasStyle.ELLIPSE_LINE) { +// val lineGeometry = GeometryTools.createGeometry(geo.geometry) +// if (lineGeometry != null) { +// val xys: Array = lineGeometry.coordinates +// if (xys != null && xys.size > 1) { +// var geoPoint: GeoPoint? = GeoPoint(xys[0].y, xys[0].x) +// val movePoint: Point = projection.geoToScreen(geoPoint) +// max_x = movePoint.x +// max_y = movePoint.y +// min_x = movePoint.x +// min_y = movePoint.y +// path.reset() +// path.moveTo(movePoint.x.toFloat(), movePoint.y.toFloat()) +// pointList.add(Point(movePoint.x, movePoint.y)) +// for (i in 1 until xys.size) { +// val x_y = xys[i] +// geoPoint = GeoPoint(x_y[0], x_y[1]) +// val point: Point = projection.geoToScreen(geoPoint) +// if (point.x > max_x) { +// max_x = point.x +// } +// if (point.x < min_x) { +// min_x = point.x +// } +// if (point.y > max_y) { +// max_y = point.y +// } +// if (point.y < min_y) { +// min_y = point.y +// } +// pointList.add(point) +// } +// path.addOval( +// RectF( +// min_x.toFloat(), +// min_y.toFloat(), +// max_x.toFloat(), +// max_y.toFloat() +// ), Path.Direction.CW +// ) +// } +// } +// val drawPath = +// CanvasView.DrawPath(pointList[0], path, width, color, canvasStyle) +// val rect = Rect(min_x, min_y, max_x, max_y) +// drawPath.rect = rect +// drawPath.pointList = pointList +// drawPaths.add(drawPath) + } else { + val lineGeometry = GeometryTools.createGeometry(geo.geometry) + if (lineGeometry != null) { + val xys: Array = lineGeometry.coordinates + if (xys.size > 1) { + var geoPoint = GeoPoint(xys[0].y, xys[0].x) + val movePoint: Point = + controller.viewportHandler.toScreenPoint(geoPoint) + max_x = movePoint.x + max_y = movePoint.y + min_x = movePoint.x + min_y = movePoint.y + path.reset() + path.moveTo(movePoint.x.toFloat(), movePoint.y.toFloat()) + pointList.add(Point(movePoint.x, movePoint.y)) + for (i in 1 until xys.size) { + val x_y = xys[i] + geoPoint = GeoPoint(x_y.y, x_y.x) + val point: Point = + controller.viewportHandler.toScreenPoint(geoPoint) + if (point.x > max_x) { + max_x = point.x + } + if (point.x < min_x) { + min_x = point.x + } + if (point.y > max_y) { + max_y = point.y + } + if (point.y < min_y) { + min_y = point.y + } + if (canvasStyle === CanvasStyle.FREE_LINE) { + val dx = abs(point.x - movePoint.x).toFloat() + val dy = abs(point.y - movePoint.y).toFloat() + if (dx >= 4 || dy >= 4) { + path.quadTo( + movePoint.x.toFloat(), + movePoint.y.toFloat(), + ((point.x + movePoint.x) / 2).toFloat(), + ((point.y + movePoint.y) / 2).toFloat() + ) //源代码是这样写的,可是我没有弄明白,为什么要这样? + movePoint.x = point.x + movePoint.y = point.y + } + } else { + path.lineTo(point.x.toFloat(), point.y.toFloat()) + } + pointList.add(point) + } + } + } + val drawPath = + CanvasView.DrawPath(pointList[0], path, width, color, canvasStyle) + val rect = Rect(min_x, min_y, max_x, max_y) + drawPath.rect = rect + drawPath.pointList = pointList + drawPaths.add(drawPath) + } + } + } + return drawPaths + } + + private fun createLineStyle(canvasStyle: CanvasStyle, width: Int, color: Int): String { + val style = StringBuilder() + if (canvasStyle === CanvasStyle.RAILWAY_LINE) { + return "4060070c004ffffff16" + } else if (canvasStyle === CanvasStyle.GREENLAND_LINE) { + return "50200b050cde3ac" + } else if (canvasStyle === CanvasStyle.WATER_LINE) { + return "50200b050abcaff" + } else if (canvasStyle === CanvasStyle.PARKING_LINE) { + return "502a6a6a6fffe98" + } + if (canvasStyle === CanvasStyle.STRAIGHT_LINE) { + style.append("2") + } else if (canvasStyle === CanvasStyle.RECT_LINE) { + style.append("3") + } else if (canvasStyle === CanvasStyle.POLY_LINE) { + style.append("6") + } else if (canvasStyle === CanvasStyle.ELLIPSE_LINE) { + style.append("7") + } else if (canvasStyle === CanvasStyle.CIRCULAR_POINT) { + style.append("9") + } else { + style.append("1") + } + if (width < 10) { + style.append("0") + } + style.append(width.toString()) + try { + var colorString = Integer.toHexString(color).toString() + if (colorString.length == 8) { + colorString = TextUtils.substring(colorString, 2, 8) + } + style.append(colorString) + } catch (e: Exception) { + e.printStackTrace() + } + return style.toString() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/omqs/ui/fragment/note/NoteFragment.kt b/app/src/main/java/com/navinfo/omqs/ui/fragment/note/NoteFragment.kt new file mode 100644 index 00000000..9d4cd8c2 --- /dev/null +++ b/app/src/main/java/com/navinfo/omqs/ui/fragment/note/NoteFragment.kt @@ -0,0 +1,135 @@ +package com.navinfo.omqs.ui.fragment.note + +import android.os.Bundle +import android.text.Editable +import android.text.TextWatcher +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.navigation.findNavController +import androidx.navigation.fragment.findNavController +import com.navinfo.omqs.R +import com.navinfo.omqs.databinding.FragmentNoteBinding +import com.navinfo.omqs.ui.dialog.FirstDialog +import com.navinfo.omqs.ui.fragment.BaseFragment +import com.navinfo.omqs.ui.other.shareViewModels +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class NoteFragment : BaseFragment(), View.OnClickListener { + private var _binding: FragmentNoteBinding? = null + private val binding get() = _binding!! + + private val viewModel by shareViewModels("note") + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + _binding = FragmentNoteBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + binding.sketchEraser.setOnClickListener(this) + binding.sketchClear.setOnClickListener(this) + binding.sketchForward.setOnClickListener(this) + binding.sketchBack.setOnClickListener(this) + binding.noteBarSave.setOnClickListener(this) + binding.noteBarCancel.setOnClickListener(this) + binding.noteBarDelete.setOnClickListener(this) + binding.noteDescription.addTextChangedListener(object : TextWatcher { + override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { + } + + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { + } + + override fun afterTextChanged(s: Editable?) { + viewModel.noteBeanDescription = s.toString() + } + }) + /** + * 数据操作结束 + */ + viewModel.liveDataFinish.observe(viewLifecycleOwner) { + if (it) + onBackPressed() + } + + /** + * 画布初始化完成 + */ + + viewModel.liveDataCanvasViewInitFinished.observe(viewLifecycleOwner) { + if (it) + arguments?.let { b -> + val id = b.getString("NoteId", "") + if (id.isNotEmpty()) { + viewModel.initData(id) + } + } + } + } + + + override fun onStart() { + super.onStart() + activity?.run { + findNavController( + R.id.main_activity_middle_fragment + ).navigate(R.id.CanvasFragment) + } + } + + override fun onStop() { + super.onStop() + activity?.run { + findNavController( + R.id.main_activity_middle_fragment + ).navigateUp() + } + } + + override fun onClick(v: View) { + when (v) { + binding.sketchEraser -> { + viewModel.onEraser() + binding.sketchEraser.isSelected = viewModel.isEraser + } + binding.sketchBack -> { + viewModel.onBack() + } + binding.sketchForward -> { + viewModel.onForward() + } + binding.sketchClear -> { + viewModel.onClear() + } + binding.noteBarSave -> { + viewModel.onSaveData() + } + binding.noteBarDelete -> { + viewModel.deleteData(requireContext()) + } + binding.noteBarCancel -> { + //返回按钮点击 + val mDialog = FirstDialog(context) + mDialog.setTitle("提示?") + mDialog.setMessage("是否退出,请确认!") + mDialog.setPositiveButton( + "确定" + ) { _, _ -> + mDialog.dismiss() + onBackPressed() + } + mDialog.setNegativeButton("取消", null) + mDialog.show() + } + } + } + + override fun onBackPressed(): Boolean { + findNavController().navigateUp() + return true + } +} \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/omqs/ui/fragment/note/NoteViewModel.kt b/app/src/main/java/com/navinfo/omqs/ui/fragment/note/NoteViewModel.kt new file mode 100644 index 00000000..d5fd927c --- /dev/null +++ b/app/src/main/java/com/navinfo/omqs/ui/fragment/note/NoteViewModel.kt @@ -0,0 +1,171 @@ +package com.navinfo.omqs.ui.fragment.note + +import android.content.Context +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.navinfo.collect.library.data.entity.NoteBean +import com.navinfo.collect.library.map.NIMapController +import com.navinfo.omqs.ui.dialog.FirstDialog +import dagger.hilt.android.lifecycle.HiltViewModel +import io.realm.Realm +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class NoteViewModel @Inject constructor( + val mapController: NIMapController +) : ViewModel() { + + lateinit var canvasView: CanvasView + + + var mNoteBean: NoteBean? = null + + + var isEraser = false + + var noteBeanDescription = "" +// /** +// * 橡皮擦开关 +// */ +// val liveEraserData = MutableLiveData(false) +// +// /** +// * 清除按钮 +// */ +// val liveClearData = MutableLiveData(false) +// +// /** +// * 回退按钮 +// */ +// val liveBackData = MutableLiveData(false) +// +// /** +// * 撤销按钮 +// */ +// val liveForward = MutableLiveData(false) + + /** + * 处理结束关闭fragment + */ + val liveDataFinish = MutableLiveData(false) + + /** + * 通知页面画布初始化完成 + */ + val liveDataCanvasViewInitFinished = MutableLiveData(false) + + fun initCanvasView(canvasView: CanvasView) { + this.canvasView = canvasView + liveDataCanvasViewInitFinished.value = true + } + + + /** + * 通知橡皮擦开关 + */ + fun onEraser() { + isEraser = !isEraser + canvasView.setEraser(isEraser) +// liveEraserData.value = !liveEraserData.value!! + } + + /** + * 通知清除 + */ + fun onClear() { + canvasView.removeAllPaint() +// liveClearData.value = true + } + + /** + * 通知回退 + */ + fun onBack() { + canvasView.back() +// liveBackData.value = true + } + + /** + * 通知撤销回退 + */ + fun onForward() { + canvasView.forward() +// liveForward.value = true + } + + /** + * 保存数据 + */ + fun onSaveData() { + viewModelScope.launch(Dispatchers.IO) { + if (canvasView.paths != null && canvasView.paths!!.isNotEmpty()) { + var noteBean = + CanvasViewHelper.createNoteBean(mapController, canvasView.paths!!) + if (mNoteBean != null) { + noteBean.id = mNoteBean!!.id + noteBean.description = noteBeanDescription + } + mNoteBean = noteBean + val realm = Realm.getDefaultInstance() + realm.executeTransaction { + it.copyToRealmOrUpdate(noteBean) + } + mapController.markerHandle.addOrUpdateNoteMark(mNoteBean!!) + liveDataFinish.postValue(true) + } + } + } + + /** + * 删除数据 + */ + fun deleteData(context: Context) { + if (mNoteBean == null) { + liveDataFinish.postValue(true) + return + } else { + val mDialog = FirstDialog(context) + mDialog.setTitle("提示?") + mDialog.setMessage("是否删除标签,请确认!") + mDialog.setPositiveButton( + "确定" + ) { dialog, _ -> + dialog.dismiss() + viewModelScope.launch(Dispatchers.IO) { + val realm = Realm.getDefaultInstance() + realm.executeTransaction { + val objects = it.where(NoteBean::class.java) + .equalTo("id", mNoteBean!!.id).findFirst() + objects?.deleteFromRealm() + } + mapController.markerHandle.removeNoteMark(mNoteBean!!) + liveDataFinish.postValue(true) + } + } + mDialog.setNegativeButton("取消", null) + mDialog.show() + } + } + + /** + * 初始化数据 + */ + fun initData(id: String) { + viewModelScope.launch(Dispatchers.IO) { + val realm = Realm.getDefaultInstance() + realm.executeTransaction { it -> + val objects = it.where(NoteBean::class.java) + .equalTo("id", id).findFirst() + mNoteBean = realm.copyFromRealm(objects) + mNoteBean?.let { bean -> + noteBeanDescription = bean.description + val list = CanvasViewHelper.createDrawPaths(mapController, bean) + canvasView.setDrawPathList(list) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable-xxhdpi/home_map_center.png b/app/src/main/res/drawable-xxhdpi/home_map_center.png new file mode 100644 index 00000000..f255a8a3 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/home_map_center.png differ diff --git a/app/src/main/res/drawable-xxhdpi/sketch_back.png b/app/src/main/res/drawable-xxhdpi/sketch_back.png new file mode 100644 index 00000000..b42d27ec Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/sketch_back.png differ diff --git a/app/src/main/res/drawable-xxhdpi/sketch_eraser.png b/app/src/main/res/drawable-xxhdpi/sketch_eraser.png new file mode 100644 index 00000000..cb57b212 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/sketch_eraser.png differ diff --git a/app/src/main/res/drawable-xxhdpi/sketch_forward.png b/app/src/main/res/drawable-xxhdpi/sketch_forward.png new file mode 100644 index 00000000..c48f4029 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/sketch_forward.png differ diff --git a/app/src/main/res/drawable/selector_sketch_eraser_bg.xml b/app/src/main/res/drawable/selector_sketch_eraser_bg.xml new file mode 100644 index 00000000..d891b1c8 --- /dev/null +++ b/app/src/main/res/drawable/selector_sketch_eraser_bg.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_vertical_dashed_line.xml b/app/src/main/res/drawable/shape_vertical_dashed_line.xml index 5aa1a4bd..b9ca9aa6 100644 --- a/app/src/main/res/drawable/shape_vertical_dashed_line.xml +++ b/app/src/main/res/drawable/shape_vertical_dashed_line.xml @@ -4,7 +4,7 @@ android:left="-300dp" android:right="-300dp"> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index eb4204c8..6a3dcc15 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -79,7 +79,7 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginRight="@dimen/top_right_drawer_btns_mr" - app:constraint_referenced_ids="main_activity_serach,main_activity_2d_3d,main_activity_camera,main_activity_trace,main_activity_calc_disance,main_activity_menu" + app:constraint_referenced_ids="main_activity_serach,main_activity_2d_3d,main_activity_camera,main_activity_trace,main_activity_calc_disance,main_activity_note,main_activity_menu" app:flow_horizontalGap="6dp" app:flow_wrapMode="aligned" app:layout_constraintRight_toLeftOf="@id/main_activity_right_fragment" @@ -90,7 +90,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="invisible" - app:constraint_referenced_ids="main_activity_serach,main_activity_2d_3d,main_activity_camera,main_activity_trace,main_activity_calc_disance" /> + app:constraint_referenced_ids="main_activity_serach,main_activity_2d_3d,main_activity_camera,main_activity_trace,main_activity_note,main_activity_calc_disance" /> + + - + app:layout_constraintRight_toLeftOf="@id/main_activity_right_fragment" /> + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_note.xml b/app/src/main/res/layout/fragment_note.xml new file mode 100644 index 00000000..6ee54057 --- /dev/null +++ b/app/src/main/res/layout/fragment_note.xml @@ -0,0 +1,235 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_phenomenon.xml b/app/src/main/res/layout/fragment_phenomenon.xml index 47d18747..73c73788 100644 --- a/app/src/main/res/layout/fragment_phenomenon.xml +++ b/app/src/main/res/layout/fragment_phenomenon.xml @@ -1,26 +1,32 @@ - - + - - \ No newline at end of file + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_problem_link.xml b/app/src/main/res/layout/fragment_problem_link.xml index d31f06f3..508cfe3e 100644 --- a/app/src/main/res/layout/fragment_problem_link.xml +++ b/app/src/main/res/layout/fragment_problem_link.xml @@ -2,13 +2,15 @@ + android:layout_width="@dimen/fragment_problem_link_width" + android:layout_height="match_parent" + android:background="@drawable/shape_middle_fragment_bg" + app:layout_constraintRight_toRightOf="parent" /> \ No newline at end of file diff --git a/app/src/main/res/navigation/middle_fragment_nav_graph.xml b/app/src/main/res/navigation/middle_fragment_nav_graph.xml index ef0d0a1d..b1897830 100644 --- a/app/src/main/res/navigation/middle_fragment_nav_graph.xml +++ b/app/src/main/res/navigation/middle_fragment_nav_graph.xml @@ -20,4 +20,10 @@ android:name="com.navinfo.omqs.ui.fragment.evaluationresult.ProblemLinkFragment" android:label="评测页面" tools:layout="@layout/fragment_problem_link"> + + \ No newline at end of file diff --git a/app/src/main/res/navigation/right_fragment_nav_graph.xml b/app/src/main/res/navigation/right_fragment_nav_graph.xml index 7aa23dc4..b47ba040 100644 --- a/app/src/main/res/navigation/right_fragment_nav_graph.xml +++ b/app/src/main/res/navigation/right_fragment_nav_graph.xml @@ -30,4 +30,11 @@ tools:layout="@layout/fragment_evaluation_result"> + + + \ No newline at end of file diff --git a/app/src/main/res/values/styleable.xml b/app/src/main/res/values/styleable.xml new file mode 100644 index 00000000..45612391 --- /dev/null +++ b/app/src/main/res/values/styleable.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 5193314e..7775f0a2 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,5 +1,20 @@ + + + +