|
@@ -28,6 +28,7 @@ import com.ys.imageProcess.ui.work.zoomStep
|
|
import com.ys.imageProcess.utils.fileSizeString
|
|
import com.ys.imageProcess.utils.fileSizeString
|
|
import com.ys.imageProcess.utils.formatDate
|
|
import com.ys.imageProcess.utils.formatDate
|
|
import com.ys.imageProcess.utils.scaleLength
|
|
import com.ys.imageProcess.utils.scaleLength
|
|
|
|
+import com.ys.imageProcess.utils.toPointF
|
|
import com.ys.imageProcess.utils.zoomToFit
|
|
import com.ys.imageProcess.utils.zoomToFit
|
|
import kotlinx.coroutines.CoroutineScope
|
|
import kotlinx.coroutines.CoroutineScope
|
|
import kotlinx.coroutines.Dispatchers
|
|
import kotlinx.coroutines.Dispatchers
|
|
@@ -54,9 +55,15 @@ class WorkViewModel : ViewModel() {
|
|
|
|
|
|
val imageState = MutableStateFlow(ImageState())
|
|
val imageState = MutableStateFlow(ImageState())
|
|
|
|
|
|
|
|
+ // 当前渲染的目标形状,像素点的数组
|
|
|
|
+ private var displayedContour = mutableListOf<PointF>()
|
|
|
|
+ private var displayedLength = mutableListOf<PointF>()
|
|
|
|
+ private var displayedWidth = mutableListOf<PointF>()
|
|
|
|
+
|
|
private var isEditingVertex = false // 正在编辑目标信息
|
|
private var isEditingVertex = false // 正在编辑目标信息
|
|
private var editingPath = -1 // 正在编辑的路径,0:轮廓,1:长,2:宽
|
|
private var editingPath = -1 // 正在编辑的路径,0:轮廓,1:长,2:宽
|
|
private var editingPoint = -1 // 正在编辑的顶点坐标的索引
|
|
private var editingPoint = -1 // 正在编辑的顶点坐标的索引
|
|
|
|
+ private var edited = false // 保存时,若有编辑操作,则调用算法重新计算
|
|
|
|
|
|
private var isAlgRunning: Boolean = false
|
|
private var isAlgRunning: Boolean = false
|
|
|
|
|
|
@@ -150,7 +157,7 @@ class WorkViewModel : ViewModel() {
|
|
}
|
|
}
|
|
|
|
|
|
val store = ProcessedData(bitmap)
|
|
val store = ProcessedData(bitmap)
|
|
- store.setMap(mMap)
|
|
|
|
|
|
+ store.updateWithStoredMap(mMap)
|
|
final = store
|
|
final = store
|
|
} else {
|
|
} else {
|
|
// 解析数据,并将结果存到本地
|
|
// 解析数据,并将结果存到本地
|
|
@@ -221,14 +228,18 @@ class WorkViewModel : ViewModel() {
|
|
}
|
|
}
|
|
|
|
|
|
fun useDefaultPaths() {
|
|
fun useDefaultPaths() {
|
|
- val sizeValid = canvasSize.width * canvasSize.height > 1
|
|
|
|
- val hasData = processedData.value.bitmap != null
|
|
|
|
- Log.i(TAG, "size valid:$sizeValid, has data: $hasData")
|
|
|
|
- if (sizeValid && hasData) {
|
|
|
|
|
|
+ val canvasValid = canvasSize.width * canvasSize.height > 1
|
|
|
|
+ val imageValid = processedData.value.bitmap != null
|
|
|
|
+ Log.i(TAG, "size valid:$canvasValid, has data: $imageValid")
|
|
|
|
+ if (canvasValid && imageValid) {
|
|
Log.i(TAG, "image:$imageSize, canvas:$canvasSize")
|
|
Log.i(TAG, "image:$imageSize, canvas:$canvasSize")
|
|
convertContour()
|
|
convertContour()
|
|
convertWidth()
|
|
convertWidth()
|
|
convertLength()
|
|
convertLength()
|
|
|
|
+
|
|
|
|
+ displayedContour = processedData.value.contour.toMutableList()
|
|
|
|
+ displayedLength = processedData.value.lengthLine.toMutableList()
|
|
|
|
+ displayedWidth = processedData.value.widthLine.toMutableList()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -315,16 +326,79 @@ class WorkViewModel : ViewModel() {
|
|
ViewAction.ShowWidth -> imageState.value =
|
|
ViewAction.ShowWidth -> imageState.value =
|
|
imageState.value.copy(showWidth = !imageState.value.showWidth)
|
|
imageState.value.copy(showWidth = !imageState.value.showWidth)
|
|
|
|
|
|
- ViewAction.SwitchEdit -> imageState.value =
|
|
|
|
- imageState.value.copy(editMode = !imageState.value.editMode)
|
|
|
|
|
|
+ ViewAction.SwitchEdit -> {
|
|
|
|
+ if (imageState.value.editMode) {
|
|
|
|
+ endEditing()
|
|
|
|
+ } else {
|
|
|
|
+ imageState.value = imageState.value.copy(editMode = true)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
updateVisibleArea()
|
|
updateVisibleArea()
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * 结束编辑
|
|
|
|
+ */
|
|
|
|
+ private fun endEditing() {
|
|
|
|
+ // 退出编辑状态
|
|
|
|
+ imageState.value = imageState.value.copy(editMode = false)
|
|
|
|
+ if (edited) {
|
|
|
|
+ edited = false
|
|
|
|
+ } else {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 使用新数据计算结果
|
|
|
|
+ val contour = mutableListOf<Double>()
|
|
|
|
+ for (p in displayedContour) {
|
|
|
|
+ contour.add(p.x.toDouble())
|
|
|
|
+ contour.add(p.y.toDouble())
|
|
|
|
+ }
|
|
|
|
+ val length = mutableListOf<Double>()
|
|
|
|
+ for (p in displayedLength) {
|
|
|
|
+ length.add(p.x.toDouble())
|
|
|
|
+ length.add(p.y.toDouble())
|
|
|
|
+ }
|
|
|
|
+ val width = mutableListOf<Double>()
|
|
|
|
+ for (p in displayedWidth) {
|
|
|
|
+ width.add(p.x.toDouble())
|
|
|
|
+ width.add(p.y.toDouble())
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ val result =
|
|
|
|
+ Process().Update(
|
|
|
|
+ processedData.value.pixelSize,
|
|
|
|
+ contour.toDoubleArray(),
|
|
|
|
+ length.toDoubleArray(),
|
|
|
|
+ width.toDoubleArray()
|
|
|
|
+ )
|
|
|
|
+ Log.i(
|
|
|
|
+ TAG,
|
|
|
|
+ "result: ${result.areaUm2},${result.perimeterUm},${result.midLengthUm},${result.midWidthUm}"
|
|
|
|
+ )
|
|
|
|
+ if (result.areaUm2 * result.perimeterUm * result.midLengthUm * result.midWidthUm <= 0) {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 更新界面
|
|
|
|
+ val data = processedData.value
|
|
|
|
+ data.updateWithAlgResult(result)
|
|
|
|
+ processedData.value = data
|
|
|
|
+ updateInfoMap()
|
|
|
|
+
|
|
|
|
+ // 保存计算结果
|
|
|
|
+ // 先用临时文件名测试
|
|
|
|
+ val name = imageData.value.name.substringBeforeLast(".")
|
|
|
|
+ val map = processedData.value.map()
|
|
|
|
+ ProcessDataStore.saveResult(map, "00001")
|
|
|
|
+ }
|
|
|
|
+
|
|
fun exitEditing() {
|
|
fun exitEditing() {
|
|
imageState.value = imageState.value.copy(editMode = false)
|
|
imageState.value = imageState.value.copy(editMode = false)
|
|
useDefaultPaths()
|
|
useDefaultPaths()
|
|
|
|
+ edited = false
|
|
}
|
|
}
|
|
|
|
|
|
fun onDrag(position: Offset) {
|
|
fun onDrag(position: Offset) {
|
|
@@ -338,6 +412,7 @@ class WorkViewModel : ViewModel() {
|
|
if (isEditingVertex) {
|
|
if (isEditingVertex) {
|
|
editingPath = pathIndex
|
|
editingPath = pathIndex
|
|
editingPoint = pointIndex
|
|
editingPoint = pointIndex
|
|
|
|
+ edited = true
|
|
}
|
|
}
|
|
|
|
|
|
Log.i(
|
|
Log.i(
|
|
@@ -362,18 +437,21 @@ class WorkViewModel : ViewModel() {
|
|
|
|
|
|
when (editingPath) {
|
|
when (editingPath) {
|
|
0 -> {
|
|
0 -> {
|
|
|
|
+ displayedContour[editingPoint] = newPixel.toPointF()
|
|
val newPath = contourPath.value.toMutableList()
|
|
val newPath = contourPath.value.toMutableList()
|
|
newPath[editingPoint] = newVertex
|
|
newPath[editingPoint] = newVertex
|
|
contourPath.value = newPath
|
|
contourPath.value = newPath
|
|
}
|
|
}
|
|
|
|
|
|
1 -> {
|
|
1 -> {
|
|
|
|
+ displayedLength[editingPoint] = newPixel.toPointF()
|
|
val newPath = lengthPath.value.toMutableList()
|
|
val newPath = lengthPath.value.toMutableList()
|
|
newPath[editingPoint] = newVertex
|
|
newPath[editingPoint] = newVertex
|
|
lengthPath.value = newPath
|
|
lengthPath.value = newPath
|
|
}
|
|
}
|
|
|
|
|
|
2 -> {
|
|
2 -> {
|
|
|
|
+ displayedWidth[editingPoint] = newPixel.toPointF()
|
|
val newPath = widthPath.value.toMutableList()
|
|
val newPath = widthPath.value.toMutableList()
|
|
newPath[editingPoint] = newVertex
|
|
newPath[editingPoint] = newVertex
|
|
widthPath.value = newPath
|
|
widthPath.value = newPath
|
|
@@ -618,7 +696,13 @@ data class ProcessedData(
|
|
private set
|
|
private set
|
|
|
|
|
|
init {
|
|
init {
|
|
- // 使用 DetectResult 设置数据
|
|
|
|
|
|
+ updateWithAlgResult(result)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 使用算法结果更新
|
|
|
|
+ */
|
|
|
|
+ fun updateWithAlgResult(result: DetectResult? = null) {
|
|
result?.let {
|
|
result?.let {
|
|
area = it.areaUm2
|
|
area = it.areaUm2
|
|
perimeter = it.perimeterUm
|
|
perimeter = it.perimeterUm
|
|
@@ -631,6 +715,26 @@ data class ProcessedData(
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * 使用本地数据更新
|
|
|
|
+ */
|
|
|
|
+ fun updateWithStoredMap(map: Map<String, Any>?) {
|
|
|
|
+ if (map == null) return
|
|
|
|
+
|
|
|
|
+ area = map[processDataKeyArea] as Double
|
|
|
|
+ perimeter = map[processDataKeyPerimeter] as Double
|
|
|
|
+ length = map[processDataKeyLength] as Double
|
|
|
|
+ width = map[processDataKeyWidth] as Double
|
|
|
|
+ pixelSize = map[processDataKeyScale] as Double
|
|
|
|
+ scaleLength = map[processDataKeyScaleLength] as Int
|
|
|
|
+
|
|
|
|
+ contour = mapArrayToPoints(map[processDataKeyContour] as ArrayList<*>)
|
|
|
|
+ lengthLine =
|
|
|
|
+ mapArrayToPoints(map[processDataKeyLengthLine] as ArrayList<*>)
|
|
|
|
+ widthLine =
|
|
|
|
+ mapArrayToPoints(map[processDataKeyWidthLine] as ArrayList<*>)
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* 将数据转为 Map
|
|
* 将数据转为 Map
|
|
*/
|
|
*/
|
|
@@ -650,26 +754,6 @@ data class ProcessedData(
|
|
return map
|
|
return map
|
|
}
|
|
}
|
|
|
|
|
|
- /**
|
|
|
|
- * 使用 Map 设置数据
|
|
|
|
- */
|
|
|
|
- fun setMap(map: Map<String, Any>?) {
|
|
|
|
- if (map == null) return
|
|
|
|
-
|
|
|
|
- area = map[processDataKeyArea] as Double
|
|
|
|
- perimeter = map[processDataKeyPerimeter] as Double
|
|
|
|
- length = map[processDataKeyLength] as Double
|
|
|
|
- width = map[processDataKeyWidth] as Double
|
|
|
|
- pixelSize = map[processDataKeyScale] as Double
|
|
|
|
- scaleLength = map[processDataKeyScaleLength] as Int
|
|
|
|
-
|
|
|
|
- contour = mapArrayToPoints(map[processDataKeyContour] as ArrayList<*>)
|
|
|
|
- lengthLine =
|
|
|
|
- mapArrayToPoints(map[processDataKeyLengthLine] as ArrayList<*>)
|
|
|
|
- widthLine =
|
|
|
|
- mapArrayToPoints(map[processDataKeyWidthLine] as ArrayList<*>)
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
private fun digitsToPoints(array: DoubleArray): List<PointF> {
|
|
private fun digitsToPoints(array: DoubleArray): List<PointF> {
|
|
val list = mutableListOf<PointF>()
|
|
val list = mutableListOf<PointF>()
|
|
for (i in array.indices step 2) {
|
|
for (i in array.indices step 2) {
|