Browse Source

feat 交付关系可用通过平面图选择空间

lihao1 3 years ago
parent
commit
3d16a53afe
26 changed files with 1149 additions and 26 deletions
  1. 23 0
      cadengine/src/main/java/cn/sagacloud/android/cadengine/Lasso.kt
  2. 2 0
      cadengine/src/main/java/cn/sagacloud/android/cadengine/types/TunableSpace.kt
  3. 10 2
      demo/src/main/AndroidManifest.xml
  4. 20 2
      demo/src/main/java/com/framework/mvvm/model/db/dao/ObjectDao.kt
  5. 3 0
      demo/src/main/java/com/framework/mvvm/model/db/dao/RelationDao.kt
  6. 2 1
      demo/src/main/java/com/framework/mvvm/model/db/entity/dict/RelConfigEntity.kt
  7. 25 4
      demo/src/main/java/com/framework/mvvm/model/repository/AdmRepository.kt
  8. 337 0
      demo/src/main/java/com/sybotan/android/demo/activities/ChooseSpaceActivity.kt
  9. 23 0
      demo/src/main/java/com/sybotan/android/demo/activities/EquipDetailActivity.kt
  10. 9 0
      demo/src/main/java/com/sybotan/android/demo/activities/PocActivity.kt
  11. 37 0
      demo/src/main/java/com/sybotan/android/demo/activities/Scene3DActivity.kt
  12. 1 0
      demo/src/main/java/com/sybotan/android/demo/activities/ServeAreaActivity.kt
  13. 38 0
      demo/src/main/java/com/sybotan/android/demo/activities/Space3DActivity.kt
  14. 6 1
      demo/src/main/java/com/sybotan/android/demo/adapter/PersonalSelectSingleAdapter.java
  15. 18 3
      demo/src/main/java/com/sybotan/android/demo/bean/RelConfigEntityPackClass.java
  16. 13 0
      demo/src/main/java/com/sybotan/android/demo/bean/SpaceInfo.java
  17. 15 0
      demo/src/main/java/com/sybotan/android/demo/bean/SpaceNameModel.java
  18. 1 0
      demo/src/main/java/com/sybotan/android/demo/retrofit/Constant.java
  19. 6 0
      demo/src/main/java/com/sybotan/android/demo/view/SelectListSinglePopupWindow.java
  20. 359 0
      demo/src/main/java/com/sybotan/android/demo/viewmodel/ChooseSpaceVM.kt
  21. 2 2
      demo/src/main/java/com/sybotan/android/demo/viewmodel/EquipDetailVM.kt
  22. 122 0
      demo/src/main/res/layout/activity_choose_space.xml
  23. 27 2
      demo/src/main/res/layout/activity_poc.xml
  24. 10 0
      demo/src/main/res/layout/activity_scene3_dactivity.xml
  25. 10 0
      demo/src/main/res/layout/activity_space3_dactivity.xml
  26. 30 9
      demo/src/main/res/layout/dialog_list_choice.xml

+ 23 - 0
cadengine/src/main/java/cn/sagacloud/android/cadengine/Lasso.kt

@@ -3,6 +3,7 @@ package cn.sagacloud.android.cadengine
 import android.graphics.Point
 import android.graphics.PointF
 import android.util.Log
+import cn.sagacloud.android.cadengine.types.PointZ
 import kotlin.math.abs
 import kotlin.math.pow
 import kotlin.math.sqrt
@@ -96,6 +97,28 @@ class Lasso {
             return nCross % 2 == 1
         }
 
+
+        fun isPolygonContainsPointZ(mPoints: ArrayList<PointZ>, point: Point): Boolean {
+            var nCross = 0
+            for (i in mPoints.indices) {
+                val p1 = mPoints[i]
+                val p2 = mPoints[(i + 1) % mPoints.size]
+                // 取多边形任意一个边,做点point的水平延长线,求解与当前边的交点个数
+                // p1p2是水平线段,要么没有交点,要么有无限个交点
+                if (p1.y == p2.y) continue
+                // point 在p1p2 底部 --> 无交点
+                if (point.y < Math.min(p1.y, p2.y)) continue
+                // point 在p1p2 顶部 --> 无交点
+                if (point.y >= Math.max(p1.y, p2.y)) continue
+                // 求解 point点水平线与当前p1p2边的交点的 X 坐标
+                val x = ((point.y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y) + p1.x).toDouble()
+                if (x > point.x) // 当x=point.x时,说明point在p1p2线段上
+                    nCross++ // 只统计单边交点
+            }
+            // 单边交点为偶数,点在多边形之外 ---
+            return nCross % 2 == 1
+        }
+
         /**
          * point3到(point1与point2的连线)的最短距离
          */

+ 2 - 0
cadengine/src/main/java/cn/sagacloud/android/cadengine/types/TunableSpace.kt

@@ -12,6 +12,8 @@ class TunableSpace() :Parcelable {
     /** 轮廓线  */
     var outLine: ArrayList<ArrayList<PointZ>>? = null
     var name: String? = null
+    var floorName: String? = null
+    var floorId: String? = null
     var objectEntity: String? = null
 
     /**

+ 10 - 2
demo/src/main/AndroidManifest.xml

@@ -36,9 +36,17 @@
         android:supportsRtl="true"
         android:theme="@style/AppTheme">
         <activity
-            android:name=".activities.EquipContainerActivity"
+            android:name=".activities.Space3DActivity"
             android:exported="true" />
-        <!-- <meta-data -->
+        <activity
+            android:name=".activities.Scene3DActivity"
+            android:exported="true" />
+        <activity
+            android:name=".activities.ChooseSpaceActivity"
+            android:exported="true" />
+        <activity
+            android:name=".activities.EquipContainerActivity"
+            android:exported="true" /> <!-- <meta-data -->
         <!-- android:name="design_width_in_dp" -->
         <!-- android:value="960" /> -->
         <!-- <meta-data -->

+ 20 - 2
demo/src/main/java/com/framework/mvvm/model/db/dao/ObjectDao.kt

@@ -29,8 +29,8 @@ interface ObjectDao {
         type: String,
     ): List<ObjectEntity>
 
-    @Query("select * from object where class_code = :code and valid = 1")
-    suspend fun getObjectByCode(code: String): List<ObjectEntity>
+    @Query("select * from object where class_code = :code and building_id =:buildingId and valid = 1")
+    suspend fun getObjectByCode(code: String, buildingId: String): List<ObjectEntity>
 
     @Query("select * from object where container_id = :objId and valid = 1")
     suspend fun getContainerObjs(objId: String): List<ObjectEntity>
@@ -57,12 +57,30 @@ interface ObjectDao {
     suspend fun getFloors(): List<ObjectEntity>
 
     /**
+     * 返回楼层类型的 ObjectEntity
+     */
+    @Query("select * from object where obj_type = 'floor' and building_id =:buildingId")
+    suspend fun getFloorsByBuildingId(buildingId: String): List<ObjectEntity>
+
+    /**
+     * 返回楼层类型的 ObjectEntity
+     */
+    @Query("select * from object where obj_type = 'floor' and id =:floorId")
+    suspend fun getFloorById(floorId: String): ObjectEntity
+
+    /**
      * 返回所有建筑 ObjectEntity
      */
     @Query("select * from object where obj_type = 'building'")
     suspend fun getBuildings(): List<ObjectEntity>
 
     /**
+     * 返回所有建筑 ObjectEntity
+     */
+    @Query("select * from object where obj_type = 'space' and floor_id =:floorId")
+    suspend fun getSpaceByFloorId(floorId: String): List<ObjectEntity>
+
+    /**
      * 更新 ObjectEntity
      */
     @Update

+ 3 - 0
demo/src/main/java/com/framework/mvvm/model/db/dao/RelationDao.kt

@@ -20,6 +20,9 @@ interface RelationDao {
     @Query("select * from relation where graph_code = :graphCode and rel_code = :relCode and valid = 1")
     suspend fun getRelationByCode(graphCode: String, relCode: String): List<RelationEntity>
 
+    @Query("select * from relation where graph_code = :graphCode and rel_code = :relCode and obj_from =:objFrom and obj_to =:objto and valid = 1")
+    suspend fun getRelByGraphCodeAndRelCodeAndObjFromAndObjTo(graphCode: String, relCode: String, objFrom: String, objto: String): RelationEntity?
+
     @Query("select * from relation where graph_code = :graphCode and rel_code = :relCode and obj_from=:equipId and valid = 1")
     suspend fun getRelationByCodeFrom(
         graphCode: String,

+ 2 - 1
demo/src/main/java/com/framework/mvvm/model/db/entity/dict/RelConfigEntity.kt

@@ -3,6 +3,7 @@ package com.framework.mvvm.model.db.entity.dict
 import androidx.room.ColumnInfo
 import androidx.room.Entity
 import androidx.room.PrimaryKey
+import java.io.Serializable
 
 /**
  * 关系配置 表
@@ -20,4 +21,4 @@ data class RelConfigEntity(
     @ColumnInfo(name = "rel_code") val relCode: String?,               // 关系的边类型代码
     @ColumnInfo(name = "rel_name") val relName: String?,               // 关系的边类型代码
     @ColumnInfo(name = "direction") val direction: String?,            // 关系方向(fixed|optional|none)
-)
+): Serializable

+ 25 - 4
demo/src/main/java/com/framework/mvvm/model/repository/AdmRepository.kt

@@ -2,7 +2,6 @@ package com.framework.mvvm.model.repository
 
 import android.content.SharedPreferences
 import android.util.Log
-import androidx.lifecycle.LiveData
 import com.framework.app.DEVICE_ID
 import com.framework.app.api.Api
 import com.framework.app.base.IRepository
@@ -10,7 +9,6 @@ import com.framework.app.http.FileInfo
 import com.framework.app.http.FileUploadInfo
 import com.framework.mvvm.model.data.*
 import com.framework.mvvm.model.db.AdmDatabase
-import com.framework.mvvm.model.db.entity.ProjectEntity
 import com.framework.mvvm.model.db.entity.dict.*
 import com.framework.mvvm.model.db.entity.task.*
 import com.framework.mvvm.model.vo.AdmRequest
@@ -184,8 +182,8 @@ class AdmRepository(
         return db.pipeDao().getPipeByIdTo(equipId, pipeType, pipeSubType)
     }
 
-    suspend fun getObjectByCode(code: String): List<ObjectEntity> {
-        return db.objectDao().getObjectByCode(code)
+    suspend fun getObjectByCode(code: String, buildingId: String): List<ObjectEntity> {
+        return db.objectDao().getObjectByCode(code, buildingId)
     }
 
     suspend fun getObjectByLocalId(localId: String): ObjectEntity? {
@@ -228,6 +226,29 @@ class AdmRepository(
         return db.majorDao().getMajors()
     }
 
+    suspend fun getSpaceByFloorId(floorId: String): List<ObjectEntity> {
+        return db.objectDao().getSpaceByFloorId(floorId)
+    }
+
+    /**
+     * 返回楼层
+     */
+    suspend fun getFloorsByBuildingId(buildingId: String): List<ObjectEntity> {
+        return db.objectDao().getFloorsByBuildingId(buildingId)
+    }
+
+
+    suspend fun getRelByGraphCodeAndRelCodeAndObjFromAndObjTo(graphCode: String, relCode: String, objFrom: String, objto: String): RelationEntity? {
+        return db.relationDao().getRelByGraphCodeAndRelCodeAndObjFromAndObjTo(graphCode, relCode, objFrom, objto)
+    }
+
+    /**
+     * 返回楼层
+     */
+    suspend fun getFloorById(floorId: String): ObjectEntity {
+        return db.objectDao().getFloorById(floorId)
+    }
+
     suspend fun getInfoByClassCodeAndCode(
         classCode: String,
         parentClassCode: String,

+ 337 - 0
demo/src/main/java/com/sybotan/android/demo/activities/ChooseSpaceActivity.kt

@@ -0,0 +1,337 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.sybotan.android.demo.activities
+
+import android.annotation.SuppressLint
+import android.graphics.PointF
+import android.os.Bundle
+import android.view.Gravity
+import android.widget.*
+import cn.sagacloud.android.cadengine.FloorScene
+import cn.sagacloud.android.cadengine.Lasso
+import cn.sagacloud.android.cadengine.items.*
+import cn.sagacloud.android.cadengine.types.*
+import cn.sagacloud.android.cadengine.types.Space
+import com.framework.mvvm.model.db.entity.task.InfosforBuild
+import com.framework.mvvm.model.db.entity.task.ObjectEntity
+import com.google.gson.Gson
+import com.sybotan.android.demo.R
+import com.sybotan.android.demo.bean.RelConfigEntityPackClass
+import com.sybotan.android.demo.bean.SpaceInfo
+import com.sybotan.android.demo.bean.SpaceNameModel
+import com.sybotan.android.demo.bean.result.*
+import com.sybotan.android.demo.entitiies.Floor
+import com.sybotan.android.demo.retrofit.Constant
+import com.sybotan.android.demo.tools.CommonUtils
+import com.sybotan.android.demo.tools.ToastUtils
+import com.sybotan.android.demo.view.SelectListSinglePopupWindow
+import com.sybotan.android.demo.viewmodel.ChooseSpaceVM
+import com.sybotan.android.graphy.SGraphyView
+import com.sybotan.base.utils.SJsonUtil
+import org.jetbrains.anko.doAsync
+import org.jetbrains.anko.uiThread
+import org.kodein.di.DI
+import org.kodein.di.DIAware
+import org.kodein.di.android.closestDI
+import java.lang.StringBuilder
+import kotlin.collections.ArrayList
+
+/**
+ * 平面图选择空间
+ */
+class ChooseSpaceActivity : BaseActivity(), DIAware {
+
+    override val di: DI by closestDI()
+
+    /** viewModel */
+    lateinit var chooseSpaceVM: ChooseSpaceVM
+
+    /** 建筑Id */
+    private lateinit var buildingId: String
+
+    /** 楼层Id */
+    private lateinit var floorId: String
+    private lateinit var projectId: String
+    private lateinit var deviceId: String
+    private var scale: Float = 0f
+    private lateinit var area: ServeAreaItem
+    private lateinit var centerPoint: PointF
+    private lateinit var position: Position
+    var tunableSpaceList = ArrayList<TunableSpaceItem>()
+    var spaceIdList = ArrayList<String>()
+
+    /** 楼层地图 */
+    private lateinit var floorMap: String
+
+    var scene = FloorScene()
+    private val gson = Gson()
+    private lateinit var floors: ArrayList<Floor>
+    private lateinit var groupRelConfigEntity: RelConfigEntityPackClass
+
+    private lateinit var graphyView: SGraphyView
+    private lateinit var close: TextView
+    private lateinit var save: TextView
+    private lateinit var floorTv: TextView
+    private lateinit var spaceName: TextView
+    private lateinit var root: LinearLayout
+    private lateinit var spaces: ArrayList<ObjectEntity>
+
+    /**
+     * 创建Activity时的回调函数
+     *
+     * @param   savedInstanceState
+     */
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_choose_space)
+        initView()
+
+        /** 初始化数据 */
+        initData()
+        graphyView.scene = scene
+
+        /** 点击监听 */
+        initListener()
+        /** 图形点击-poc业务 */
+        initSingleTopUp()
+        /** 网络请求回调处理 */
+        initViewModel()
+
+        return
+    } // Function onCreate()
+
+
+    private fun initView() {
+        graphyView = findViewById(R.id.graphyView)
+        close = findViewById(R.id.close)
+        save = findViewById(R.id.save)
+        floorTv = findViewById(R.id.floorTv)
+        root = findViewById(R.id.root)
+        spaceName = findViewById(R.id.spaceName)
+    }
+
+    /**
+     * 初始化数据
+     */
+    private fun initData() {
+        val params = intent.getBundleExtra("params")!!
+        buildingId = params.getString("buildingId", "")!!
+        floorId = params.getString("floorId", "")!!
+        floorMap = params.getString("floorMap", "")!!
+        projectId = params.getString("projectId", "")!!
+        deviceId = params.getString("deviceId", "")!!
+        scale = params.getFloat("scale")!!
+        centerPoint = params.getParcelable("centerPoint")!!
+        groupRelConfigEntity = (params.getSerializable("groupRelConfigEntity") as RelConfigEntityPackClass?)!!
+        position = (params.getSerializable("position") as Position?)!!
+        val p = Point()
+        p.mX = position.x.toFloat()
+        p.mY = position.y.toFloat()
+        val equipItem = EquipItem(this, p)
+        equipItem.zOrder = 100000f
+        scene.addItem(equipItem)
+    }
+
+
+    /**
+     * 图形点击事件
+     * */
+    private fun initSingleTopUp() {
+        scene.setOnSingleTopUp(object : FloorScene.OnSingleTopUp {
+            @SuppressLint("SetJavaScriptEnabled")
+            override fun onSingUp(x: Float, y: Float) {
+
+                for (space in tunableSpaceList) {
+                    val isContain = Lasso.isPolygonContainsPoint(space.mPoints, android.graphics.Point(x.toInt(), -y.toInt()))
+                    if (isContain && space.data.floorName == floorTv.text.toString()) {
+                        scene.removeItem(space)
+                        tunableSpaceList.remove(space)
+                        initSpaceName()
+                        for (sp in spaces) {
+                            val info = gson.fromJson(sp.infos, SpaceInfo::class.java)
+                            val isContains = Lasso.isPolygonContainsPointZ(info.outline!![0][0], android.graphics.Point(x.toInt(), -y.toInt()))
+                            if (isContains) {
+                                if (spaceIdList.contains(sp.id)) {
+                                    spaceIdList.remove(sp.id)
+                                    return
+                                }
+                            }
+                        }
+                    }
+                }
+
+                for (space in scene.spaceList) {
+                    val isContain = Lasso.isPolygonContainsPoint(space.mPoints, android.graphics.Point(x.toInt(), -y.toInt()))
+                    if (isContain) {
+                        val tunableSpace = TunableSpace()
+                        tunableSpace.outLine = space.data.outLine
+                        tunableSpace.name = space.data.name
+                        tunableSpace.floorName = floorTv.text.toString()
+                        tunableSpace.floorId = floorId
+                        val item = TunableSpaceItem(tunableSpace)
+                        item.zOrder = 99996f
+                        tunableSpaceList.add(item)
+                        scene.addItem(item)
+                        initSpaceName()
+                        for (sp in spaces) {
+                            val obj = sp.infos!!.asJsonObject
+                            val info = gson.fromJson(obj, SpaceInfo::class.java)
+                            val isContains = Lasso.isPolygonContainsPointZ(info!!.outline!![0][0], android.graphics.Point(x.toInt(), -y.toInt()))
+                            if (isContains) {
+                                spaceIdList.add(sp.id)
+                                break
+                            }
+                        }
+                        break
+                    }
+                }
+            }
+
+        })
+    }
+
+    /**
+     * 页面全部监听事件
+     */
+    private fun initListener() {
+        floorTv.setOnClickListener {
+            val pop = SelectListSinglePopupWindow(this)
+            pop.setGenList(floors, Constant.TYPE5)
+            pop.setTitle(true, "选择对象")
+            pop.showAtLocation(root, Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL, 0, 0)
+            pop.setOnItemClickListener {
+                val floor = floors[it]
+                floorTv.text = floor.localName
+                floorId = floor.id
+                chooseSpaceVM.getFloorMap(floorId)
+                chooseSpaceVM.getSpaces(floorId)
+            }
+        }
+        close.setOnClickListener { finish() }
+        save.setOnClickListener {
+            if (CommonUtils.IsNull(tunableSpaceList)) {
+                ToastUtils.showMyToast("请绘制服务区域")
+                return@setOnClickListener
+            }
+            chooseSpaceVM.insRel(deviceId, spaceIdList, groupRelConfigEntity)
+        }
+    }
+
+    /**
+     * 初始化viewModel
+     */
+    private fun initViewModel() {
+        chooseSpaceVM = ChooseSpaceVM(this.application, { name, params ->
+            when (name) {
+                /** 加载地图 */
+                ChooseSpaceVM.MAP_LOAD -> {
+                    val floorOfflineData = gson.fromJson(params.toString(), FloorData::class.java)
+                    doAsync {
+                        scene.loadData(floorOfflineData)
+                        uiThread {
+                            graphyView.setCenterPoint(centerPoint, scale)
+                        }
+                    }
+                }
+
+                /** 物业空间 */
+                ChooseSpaceVM.SERVE_AREAS -> {
+                    val param = params as ArrayList<TunableSpace>
+                    for (space in param) {
+                        spaceIdList.add(space.id!!)
+                        val item = TunableSpaceItem(space)
+                        item.zOrder = 99996f
+                        if (space.floorId == floorId) {
+                            scene.addItem(item)
+                        }
+                        tunableSpaceList.add(item)
+                    }
+                    initSpaceName()
+                }
+                ChooseSpaceVM.FLOORS_LIST -> {
+                    floors = params as ArrayList<Floor>
+                    for (floor in floors) {
+                        if (floorId == floor.id) {
+                            floorTv.setText(floor.localName)
+                            chooseSpaceVM.getSpaces(floorId)
+                        }
+                    }
+                }
+                ChooseSpaceVM.FLOOR_MAP -> {
+                    val floorOfflineData = SJsonUtil.fromJson(params.toString(), FloorData::class.java)
+                    doAsync {
+                        scene = FloorScene()
+                        graphyView.scene = scene
+                        scene.loadData(floorOfflineData!!)
+                        uiThread {
+                            initSingleTopUp()
+                            for (space in tunableSpaceList) {
+                                if (space.data.floorId == floorId) {
+                                    scene.addItem(space)
+                                }
+                            }
+                            initSpaceName()
+                        }
+                    }
+                }
+                ChooseSpaceVM.SPACES -> {
+                    spaces = params as ArrayList<ObjectEntity>
+                }
+
+            }
+        }, this, buildingId, floorId, projectId)
+        chooseSpaceVM.getMap()
+        chooseSpaceVM.getFloorList()
+        chooseSpaceVM.getRel(deviceId, groupRelConfigEntity)
+    }
+
+    private fun initSpaceName() {
+        val sb = StringBuilder()
+        val others = ArrayList<SpaceNameModel>()
+        sb.append(floorTv.text.toString()).append(":")
+        for (space in tunableSpaceList) {
+            if (space.data.floorName == floorTv.text.toString()) {
+                sb.append(space.data.name).append("、")
+            } else {
+                var has = false
+                for (other in others) {
+                    if (other.name == space.data.floorName) {
+                        other.size++
+                        has = true
+                    }
+                }
+                if (!has) {
+                    others.add(SpaceNameModel(space.data.floorName, 1))
+                }
+            }
+        }
+        sb.append("\n\n其他层:\n")
+        for (other in others) {
+            sb.append("${other.name}(${other.size})、")
+        }
+        spaceName.text = sb.toString()
+    }
+
+
+} // Class GraphyActivity

+ 23 - 0
demo/src/main/java/com/sybotan/android/demo/activities/EquipDetailActivity.kt

@@ -405,6 +405,26 @@ class EquipDetailActivity : BaseActivity(), View.OnTouchListener {
                     val pop = SelectListSinglePopupWindow(this@EquipDetailActivity)
                     pop.setList(equipObjects, Constant.TYPE2)
                     pop.setTitle(true, "选择对象")
+                    if (groupRelConfigEntity.targetTypes[0].targetCode == "GeneralZone") {
+                        pop.setChooseSpace()
+                    }
+                    pop.chooseSpace.setOnClickListener {
+                        val intent = Intent(this, ChooseSpaceActivity::class.java)
+                        val bundle = Bundle()
+                        bundle.putString("buildingId", buildingId)
+                        bundle.putString("floorId", floorId)
+                        bundle.putString("projectId", projectId)
+                        bundle.putFloat("scale", scale)
+                        bundle.putString("floorMap", floorMap)
+                        bundle.putParcelable("centerPoint", centerPoint)
+                        bundle.putSerializable("groupRelConfigEntity", groupRelConfigEntity)
+                        bundle.putSerializable("position", position)
+                        val id = if (TextUtils.isEmpty(deviceId)) uuid else deviceId
+                        bundle.putString("deviceId", id)
+                        intent.putExtra("params", bundle)
+                        startActivity(intent)
+                        pop.dismissImmediately()
+                    }
                     pop.showAtLocation(root, Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL, 0, 0)
                     pop.setOnItemClickListener {
                         if (!CommonUtils.IsNull(list)) {
@@ -492,6 +512,9 @@ class EquipDetailActivity : BaseActivity(), View.OnTouchListener {
 
     override fun onResume() {
         super.onResume()
+        if (equipEntity != null) {
+            equipVM.getRelConfig(equipEntity!!, deviceId, uuid)
+        }
         equipVM.getServeArea(if (TextUtils.isEmpty(deviceId)) uuid else deviceId)
     }
 

+ 9 - 0
demo/src/main/java/com/sybotan/android/demo/activities/PocActivity.kt

@@ -50,6 +50,10 @@ class PocActivity : BaseActivity(), DIAware {
 
     private lateinit var frameBtn: Button
 
+    private lateinit var space3DBtn: Button
+
+    private lateinit var scene3DBtn: Button
+
     private lateinit var version: TextView
 
     override fun onCreate(savedInstanceState: Bundle?) {
@@ -61,9 +65,14 @@ class PocActivity : BaseActivity(), DIAware {
         dictBtn = findViewById(R.id.dictBtn)
         configBtn = findViewById(R.id.configBtn)
         frameBtn = findViewById(R.id.frameBtn)
+        space3DBtn = findViewById(R.id.space3DBtn)
+        scene3DBtn = findViewById(R.id.scene3DBtn)
 
         version = findViewById(R.id.version)
 
+        space3DBtn.setOnClickListener { startActivity<Space3DActivity>() }
+        scene3DBtn.setOnClickListener { startActivity<Scene3DActivity>() }
+
         downloadBtn.setOnClickListener {
             mVm.downloadBuilding(sp) {
                 // ToastUtils.showMyToast("下载完成")

+ 37 - 0
demo/src/main/java/com/sybotan/android/demo/activities/Scene3DActivity.kt

@@ -0,0 +1,37 @@
+package com.sybotan.android.demo.activities
+
+import androidx.appcompat.app.AppCompatActivity
+import android.os.Bundle
+import android.webkit.WebSettings
+import android.webkit.WebView
+import android.webkit.WebViewClient
+import com.sybotan.android.demo.R
+
+class Scene3DActivity : AppCompatActivity() {
+    private lateinit var webview: WebView
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_scene3_dactivity)
+        webview = findViewById(R.id.webview)
+        val settings: WebSettings = webview.getSettings()
+        settings.javaScriptEnabled = true
+        settings.defaultTextEncodingName = "utf-8"
+        settings.builtInZoomControls = true
+        settings.loadsImagesAutomatically = true
+        settings.layoutAlgorithm = WebSettings.LayoutAlgorithm.SINGLE_COLUMN
+        webview.webViewClient = MyWebViewClient()
+        webview.loadUrl("http://60.205.177.43:8000/APP/#/?PageType=2")
+    }
+
+    class MyWebViewClient : WebViewClient() {
+        //兼容低版本
+        override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
+            view.loadUrl(url)
+            return true
+        }
+
+        override fun onPageFinished(view: WebView, url: String) {
+            super.onPageFinished(view, url)
+        }
+    }
+}

+ 1 - 0
demo/src/main/java/com/sybotan/android/demo/activities/ServeAreaActivity.kt

@@ -56,6 +56,7 @@ import kotlin.collections.ArrayList
 
 /**
  * 设备服务区域绘制
+ * 2021-11-12功能废弃
  */
 class ServeAreaActivity : BaseActivity(), DIAware {
 

+ 38 - 0
demo/src/main/java/com/sybotan/android/demo/activities/Space3DActivity.kt

@@ -0,0 +1,38 @@
+package com.sybotan.android.demo.activities
+
+import androidx.appcompat.app.AppCompatActivity
+import android.os.Bundle
+import android.webkit.WebSettings
+import android.webkit.WebView
+import android.webkit.WebViewClient
+import com.sybotan.android.demo.R
+
+class Space3DActivity : AppCompatActivity() {
+
+    private lateinit var webview: WebView
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_space3_dactivity)
+        webview = findViewById(R.id.webview)
+        val settings: WebSettings = webview.getSettings()
+        settings.javaScriptEnabled = true
+        settings.defaultTextEncodingName = "utf-8"
+        settings.builtInZoomControls = true
+        settings.loadsImagesAutomatically = true
+        settings.layoutAlgorithm = WebSettings.LayoutAlgorithm.SINGLE_COLUMN
+        webview.webViewClient = MyWebViewClient()
+        webview.loadUrl("http://60.205.177.43:8000/APP/#/?PageType=1")
+    }
+
+    class MyWebViewClient : WebViewClient() {
+        //兼容低版本
+        override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
+            view.loadUrl(url)
+            return true
+        }
+
+        override fun onPageFinished(view: WebView, url: String) {
+            super.onPageFinished(view, url)
+        }
+    }
+}

+ 6 - 1
demo/src/main/java/com/sybotan/android/demo/adapter/PersonalSelectSingleAdapter.java

@@ -16,6 +16,7 @@ import com.framework.mvvm.model.db.entity.dict.MajorEntity;
 import com.framework.mvvm.model.db.entity.task.ObjectEntity;
 import com.framework.mvvm.model.db.entity.task.Options;
 import com.sybotan.android.demo.R;
+import com.sybotan.android.demo.entitiies.Floor;
 import com.sybotan.android.demo.retrofit.Constant;
 
 import java.util.ArrayList;
@@ -71,7 +72,11 @@ public class PersonalSelectSingleAdapter extends RecyclerView.Adapter<PersonalSe
         }
         if (type.equals(Constant.TYPE4)) {
             EquipItem options = (EquipItem) item;
-            holder.choice_name.setText(options.getData().getType()+":"+options.getData().getName());
+            holder.choice_name.setText(options.getData().getType() + ":" + options.getData().getName());
+        }
+        if (type.equals(Constant.TYPE5)) {
+            Floor options = (Floor) item;
+            holder.choice_name.setText(options.getLocalName());
         }
         if (selectPosition > 0 && selectPosition - 1 == position) {
             holder.choice_name.setTextColor(context.getResources().getColor(R.color.blue_2f48b7));

+ 18 - 3
demo/src/main/java/com/sybotan/android/demo/bean/RelConfigEntityPackClass.java

@@ -1,7 +1,11 @@
 package com.sybotan.android.demo.bean;
 
+import android.os.Parcel;
+import android.os.Parcelable;
+
 import com.framework.mvvm.model.db.entity.dict.RelConfigEntity;
 
+import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Objects;
 
@@ -9,18 +13,22 @@ import java.util.Objects;
  * Created by lihao.
  * Date: 2021/10/18
  */
-public class RelConfigEntityPackClass {
+public class RelConfigEntityPackClass implements Serializable {
     public RelConfigEntity entity;
     public String fromName;
     public String toName;
+
+    public RelConfigEntityPackClass() {
+    }
+
     public ArrayList<TargetRelType> targetTypes = new ArrayList<>();
 
     public boolean sameRelConfig(RelConfigEntity cfg) {
         return Objects.equals(entity.getGraphCode(), cfg.getGraphCode()) && Objects.equals(entity.getRelCode(), cfg.getRelCode());
     }
 
-    public static class TargetRelType {
-        public boolean canFrom ;
+    public static class TargetRelType implements Serializable {
+        public boolean canFrom;
         public boolean canTo;
         public boolean connect;
         public String srcCode;
@@ -28,5 +36,12 @@ public class RelConfigEntityPackClass {
         public String relCode;
         public String targetCode;
         public String direction;
+
+        public TargetRelType() {
+        }
+
+
     }
+
+
 }

+ 13 - 0
demo/src/main/java/com/sybotan/android/demo/bean/SpaceInfo.java

@@ -0,0 +1,13 @@
+package com.sybotan.android.demo.bean;
+
+import java.util.ArrayList;
+
+import cn.sagacloud.android.cadengine.types.PointZ;
+
+/**
+ * Created by lihao.
+ * Date: 2021/11/16
+ */
+public class SpaceInfo {
+    public ArrayList<ArrayList<ArrayList<PointZ>>> outline = new ArrayList<>();
+}

+ 15 - 0
demo/src/main/java/com/sybotan/android/demo/bean/SpaceNameModel.java

@@ -0,0 +1,15 @@
+package com.sybotan.android.demo.bean;
+
+/**
+ * Created by lihao.
+ * Date: 2021/11/15
+ */
+public class SpaceNameModel {
+    public String name;
+    public int size;
+
+    public SpaceNameModel(String name, int size) {
+        this.name = name;
+        this.size = size;
+    }
+}

+ 1 - 0
demo/src/main/java/com/sybotan/android/demo/retrofit/Constant.java

@@ -23,4 +23,5 @@ public class Constant {
     public static final String TYPE2 = "equip";
     public static final String TYPE3 = "major";
     public static final String TYPE4 = "EquipItem";
+    public static final String TYPE5 = "space";
 }

+ 6 - 0
demo/src/main/java/com/sybotan/android/demo/view/SelectListSinglePopupWindow.java

@@ -43,6 +43,7 @@ public class SelectListSinglePopupWindow extends PopupWindow {
     DisplayMetrics dm;
 
     private TextView title;
+    public TextView chooseSpace;
     private Button btn1, btn_cancel;
     private RecyclerView recyclerview;
     private LinearLayout searchLinear;
@@ -78,6 +79,7 @@ public class SelectListSinglePopupWindow extends PopupWindow {
         btn_cancel = (Button) mMenuView.findViewById(R.id.btn_cancel);
         searchLinear = (LinearLayout) mMenuView.findViewById(R.id.search_linear);
         searchEdt = (EditText) mMenuView.findViewById(R.id.search_edt);
+        chooseSpace = (TextView) mMenuView.findViewById(R.id.chooseSpace);
         searchDelete = (ImageView) mMenuView.findViewById(R.id.search_delete);
         searchLinear.setVisibility(View.VISIBLE);
         //取消按钮
@@ -225,6 +227,10 @@ public class SelectListSinglePopupWindow extends PopupWindow {
         adapter.notifyDataSetChanged();
     }
 
+    public void setChooseSpace(){
+        chooseSpace.setVisibility(View.VISIBLE);
+    }
+
 
     private int gravity = Gravity.BOTTOM;
 

+ 359 - 0
demo/src/main/java/com/sybotan/android/demo/viewmodel/ChooseSpaceVM.kt

@@ -0,0 +1,359 @@
+package com.sybotan.android.demo.viewmodel
+
+import android.app.Application
+import android.graphics.PointF
+import android.text.TextUtils
+import androidx.lifecycle.viewModelScope
+import cn.hutool.core.util.IdUtil
+import cn.sagacloud.android.cadengine.Lasso
+import cn.sagacloud.android.cadengine.items.PipeLineItem
+import cn.sagacloud.android.cadengine.items.PointItem
+import cn.sagacloud.android.cadengine.items.TunableSpaceItem
+import cn.sagacloud.android.cadengine.types.*
+import com.framework.mvvm.model.db.entity.task.*
+import com.framework.mvvm.model.repository.AdmRepository
+import com.google.gson.Gson
+import com.google.gson.JsonArray
+import com.google.gson.reflect.TypeToken
+import com.sybotan.android.demo.activities.BaseActivity
+import com.sybotan.android.demo.bean.RelConfigEntityPackClass
+import com.sybotan.android.demo.bean.RelationPackClass
+import com.sybotan.android.demo.bean.SpaceInfo
+import com.sybotan.android.demo.bean.result.*
+import com.sybotan.android.demo.entitiies.Floor
+import com.sybotan.android.demo.entitiies.Info
+import com.sybotan.android.demo.entitiies.Statistics
+import com.sybotan.android.demo.retrofit.BaseViewModelInterface
+import com.sybotan.android.demo.tools.CommonUtils
+import com.sybotan.android.demo.tools.ToastUtils
+import com.sybotan.base.utils.SJsonUtil
+import kotlinx.coroutines.launch
+import org.kodein.di.DI
+import org.kodein.di.DIAware
+import org.kodein.di.android.x.closestDI
+import org.kodein.di.instance
+import java.util.*
+import kotlin.collections.ArrayList
+
+
+/**
+ * Created by lihao.
+ * Date: 2021/6/9
+ */
+class ChooseSpaceVM(
+    app: Application,
+    b: BaseViewModelInterface?, activity: BaseActivity?, //建筑id
+    private val buildingId: String, //楼层id
+    private val floorId: String,
+    private val projectId: String
+) : BaseViewModel(app, b, activity), DIAware {
+    private val gson = Gson()
+
+    override val di: DI by closestDI()
+    private val repo: AdmRepository by instance()
+
+
+    fun getMap() {
+        viewModelScope.launch {
+            val floors = repo.getFloors()
+            for (floor in floors) {
+                if (floor.id == floorId) {
+                    if (TextUtils.isEmpty(floor.floorMap)) {
+                        ToastUtils.showMyToast("没有地图")
+                        break
+                    }
+                    val floorOfflineData =
+                        SJsonUtil.fromJson(floor.floorMap!!, FloorData::class.java)
+                    mEmitter.SendDirective(MAP_LOAD, gson.toJson(floorOfflineData))
+                    break
+                }
+            }
+
+        }
+    }
+
+
+    fun insServeAreas(deviceId: String, spaces: ArrayList<TunableSpaceItem>) {
+        viewModelScope.launch {
+            val geom = ArrayList<ArrayList<ArrayList<PointZ>>>()
+            for (space in spaces) {
+                geom.add(space.data.outLine!!)
+            }
+            var entity = repo.getServeAreaByObjId(deviceId)
+            if (entity == null) {
+                entity = ServeAreaEntity(
+                    id = IdUtil.simpleUUID(),
+                    projectId = projectId,
+                    buildingId = buildingId,
+                    floorId = floorId,
+                    state = "1",
+                    uploadFlag = null,
+                    valid = 1,
+                    creator = null,
+                    creationTime = null,
+                    modifier = null,
+                    modifiedTime = null,
+                    objId = deviceId,
+                    geomType = "polygon",
+                    geom = gson.toJsonTree(geom),
+                    serveType = null, remark = null
+                )
+            } else {
+                entity.geom = gson.toJsonTree(geom)
+                entity.state = "1"
+            }
+            repo.insServeArea(entity)
+            mActivity.finish()
+        }
+    }
+
+    fun getServeArea(deviceId: String) {
+        viewModelScope.launch {
+            val entity = repo.getServeAreaByObjId(deviceId)
+            if (entity != null) {
+                val array = entity.geom!!.asJsonArray
+                if (array[0].isJsonObject) {
+                    val ar = gson.fromJson<List<PointF>>(
+                        gson.toJson(entity.geom),
+                        object : TypeToken<List<PointF?>?>() {}.type
+                    )
+                    mEmitter.SendDirective(SERVE_AREA, ar)
+                } else {
+                    val ar = gson.fromJson<List<ArrayList<ArrayList<PointZ>>>>(
+                        gson.toJson(entity.geom),
+                        object : TypeToken<List<ArrayList<ArrayList<PointZ>>>>() {}.type
+                    )
+                    mEmitter.SendDirective(SERVE_AREAS, ar)
+                }
+            }
+        }
+    }
+
+
+    fun getFloorList() {
+        viewModelScope.launch {
+            val floors = repo.getFloorsByBuildingId(buildingId)
+            var floorList = ArrayList<Floor>()
+            for (floor in floors) {
+                val infos = Gson().fromJson(floor.infos, InfosforBuild::class.java)
+                var floorMap = ""
+                if (TextUtils.isEmpty(infos.floorMap)) {
+                    floorMap = ""
+                } else {
+                    floorMap = infos.floorMap
+                }
+                var localId = ""
+                if (TextUtils.isEmpty(floor.localId)) {
+                    localId = ""
+                } else {
+                    localId = floor.localId!!
+                }
+                floorList.add(
+                    Floor(
+                        bimIdPre = "",
+                        buildingId = floor.buildingId!!,
+                        count = 0.0,
+                        createTime = "",
+                        floorSequenceID = infos.floorSequenceID,
+                        id = floor.id,
+                        lastUpdate = "",
+                        localId = localId,
+                        localName = floor.localName!!,
+                        modelId = "",
+                        name = floor.name ?: "",
+                        objectType = "floor",
+                        projectId = floor.projectId!!,
+                        statistics = Statistics(),
+                        infos = Info("", floorMap)
+                    )
+                )
+            }
+            floorList.sortByDescending { floor -> floor.floorSequenceID }
+            mEmitter.SendDirective(FLOORS_LIST, floorList)
+        }
+
+    }
+
+    fun getFloorMap(floorId: String) {
+        viewModelScope.launch {
+            val floors = repo.getFloors()
+            for (floor in floors) {
+                if (floor.id == floorId) {
+                    if (TextUtils.isEmpty(floor.floorMap)) {
+                        ToastUtils.showMyToast("没有地图")
+                        break
+                    }
+                    val floorOfflineData =
+                        SJsonUtil.fromJson(floor.floorMap!!, FloorData::class.java)
+                    mEmitter.SendDirective(FLOOR_MAP, gson.toJson(floorOfflineData))
+                    break
+                }
+            }
+
+        }
+    }
+
+    fun insRel(deviceId: String, spaceIds: ArrayList<String>, groupRelConfigEntity: RelConfigEntityPackClass) {
+        viewModelScope.launch {
+            val rels = getRelations(groupRelConfigEntity, deviceId)
+            for (rel in rels) {
+                rel.entity.valid = 0
+                repo.insRelation(rel.entity)
+            }
+            for (id in spaceIds) {
+                val objFrom: String
+                val objto: String
+                if (groupRelConfigEntity.targetTypes[0].canFrom) {
+                    objto = deviceId
+                    objFrom = id
+                } else {
+                    objFrom = deviceId
+                    objto = id
+                }
+                val en = repo.getRelByGraphCodeAndRelCodeAndObjFromAndObjTo(groupRelConfigEntity.entity.graphCode!!, groupRelConfigEntity.entity.relCode!!, objFrom, objto)
+                if (en == null) {
+                    val relEntity = RelationEntity(
+                        id = IdUtil.simpleUUID(),
+                        projectId = projectId,
+                        buildingId = buildingId,
+                        floorId = floorId,
+                        graphCode = groupRelConfigEntity.entity.graphCode,
+                        graphId = null,
+                        groupCode = null,
+                        relCode = groupRelConfigEntity.entity.relCode,
+                        relValue = null,
+                        objFrom = objFrom,
+                        objTo = objto,
+                        createApp = null,
+                        updateApp = null,
+                        creator = null,
+                        creationTime = "",
+                        modifiedTime = "",
+                        modifier = null,
+                        clientId = null,
+                        clientDevice = null,
+                        uploadFlag = null,
+                        deliveryState = null,
+                        valid = 1, d2mState = null, objFromLocalId = null, objToLocalId = null, state = "1"
+                    )
+                    repo.insRelation(relEntity)
+                }
+            }
+            mActivity.finish()
+        }
+    }
+
+    fun getRel(deviceId: String, groupRelConfigEntity: RelConfigEntityPackClass) {
+        viewModelScope.launch {
+            val rels = getRelations(groupRelConfigEntity, deviceId)
+            val spaces = ArrayList<TunableSpace>()
+            for (rel in rels) {
+                val objEntity: ObjectEntity
+                if (rel.entity.objFrom == deviceId) {
+                    objEntity = repo.getObject(rel.entity.objTo!!)!!
+                } else {
+                    objEntity = repo.getObject(rel.entity.objFrom!!)!!
+                }
+                val obj = objEntity.infos!!.asJsonObject
+                val info = gson.fromJson(obj, SpaceInfo::class.java)
+//                spaces.add(info.outline[0])
+
+                val tunableSpace = TunableSpace()
+                tunableSpace.outLine = info.outline[0]
+                tunableSpace.name = objEntity.localName
+                tunableSpace.id = objEntity.id
+                val floor = repo.getFloorById(objEntity.floorId!!)
+                tunableSpace.floorName = floor.localName
+                tunableSpace.floorId = objEntity.floorId
+                spaces.add(tunableSpace)
+            }
+            mEmitter.SendDirective(SERVE_AREAS, spaces)
+        }
+    }
+
+    private suspend fun ChooseSpaceVM.getRelations(
+        groupRelConfigEntity: RelConfigEntityPackClass,
+        deviceId: String
+    ): ArrayList<RelationPackClass> {
+        val rels = ArrayList<RelationPackClass>()
+        for (child in groupRelConfigEntity.targetTypes) {
+            if (child.canFrom) {
+                val to = repo.getRelByCodeTo(
+                    groupRelConfigEntity.entity.graphCode!!,
+                    groupRelConfigEntity.entity.relCode!!,
+                    deviceId
+                )
+                loadRelation(to, child, groupRelConfigEntity, rels)
+            }
+
+            if (child.canTo) {
+                val from = repo.getRelByCodeFrom(
+                    groupRelConfigEntity.entity.graphCode!!,
+                    groupRelConfigEntity.entity.relCode!!,
+                    deviceId
+                )
+                loadRelation(from, child, groupRelConfigEntity, rels)
+            }
+        }
+        return rels
+    }
+
+    private suspend fun loadRelation(
+        to: List<RelationEntity>,
+        child: RelConfigEntityPackClass.TargetRelType,
+        parent: RelConfigEntityPackClass,
+        rel: ArrayList<RelationPackClass>
+    ) {
+        bindRelationEntityName(to)
+        if (!CommonUtils.IsNull(to)) {
+            for (t in to) {
+                if (child.targetCode.equals(parent.entity.classCodeTo)) {
+                    val pack = RelationPackClass()
+                    pack.entity = t
+                    pack.targetPipeType = child
+                    rel.add(pack)
+                }
+            }
+        }
+    }
+
+    private suspend fun bindRelationEntityName(
+        entitys: List<RelationEntity>
+    ) {
+        for (rel in entitys) {
+            val from = repo.getObject(rel.objFrom!!)
+            if (from == null) {
+                rel.objFromLocalId = "该设备"
+            } else {
+                rel.objFromLocalId =
+                    if (from!!.id.startsWith("Eq")) from!!.localId else from!!.localName
+            }
+            val to = repo.getObject(rel.objTo!!)
+            if (to == null) {
+                rel.objToLocalId = "该设备"
+            } else {
+                rel.objToLocalId = if (to!!.id.startsWith("Eq")) to!!.localId else to!!.localName
+            }
+        }
+    }
+
+    fun getSpaces(floorId: String) {
+        viewModelScope.launch {
+            val spaces = repo.getSpaceByFloorId(floorId)
+            mEmitter.SendDirective(SPACES, spaces)
+        }
+    }
+
+
+    companion object {
+        const val MAP_LOAD = "MAP_LOAD"
+
+        //服务区域
+        const val SERVE_AREA = "SERVE_AREA"
+        const val SERVE_AREAS = "SERVE_AREAS"
+        const val FLOORS_LIST = "FLOORS_LIST"
+        const val FLOOR_MAP = "FLOOR_MAP"
+        const val SPACES = "SPACES"
+
+    }
+}

+ 2 - 2
demo/src/main/java/com/sybotan/android/demo/viewmodel/EquipDetailVM.kt

@@ -497,7 +497,7 @@ class EquipDetailVM(
         viewModelScope.launch {
             val objects: ArrayList<ObjectEntity> = ArrayList()
             for (type in group.targetTypes) {
-                val objs = repo.getObjectByCode(type.targetCode!!)
+                val objs = repo.getObjectByCode(type.targetCode!!, buildingId)
                 if (!CommonUtils.IsNull(objs)) {
                     objects.addAll(objs)
                 }
@@ -513,7 +513,7 @@ class EquipDetailVM(
         viewModelScope.launch {
             val objects: ArrayList<ObjectEntity> = ArrayList()
             for (type in group.targetTypes) {
-                val objs = repo.getObjectByCode(type.targetCode!!)
+                val objs = repo.getObjectByCode(type.targetCode!!, buildingId)
                 if (!CommonUtils.IsNull(objs)) {
                     objects.addAll(objs)
                 }

+ 122 - 0
demo/src/main/res/layout/activity_choose_space.xml

@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ *********************************************************************************************************************
+  ~
+  ~               iFHS7.
+  ~              ;BBMBMBMc                  rZMBMBR              BMB
+  ~              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+  ~     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+  ~     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+  ~      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+  ~     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+  ~     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+  ~     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+  ~         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+  ~     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+  ~      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+  ~         i0BM: SWKHKGO  MBDv
+  ~           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+  ~              ,  XMW  ..
+  ~                  r                                                                     All rights reserved.
+  ~
+  ~ *********************************************************************************************************************
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/root"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/white"
+    android:orientation="vertical"
+    tools:context="com.sybotan.android.demo.activities.GraphyActivity">
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1">
+
+        <com.sybotan.android.graphy.SGraphyView
+            android:id="@+id/graphyView"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_marginBottom="5dp" />
+
+        <TextView
+            android:id="@+id/floorTv"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="16dp"
+            android:layout_marginTop="16dp"
+            android:background="@color/grey_200"
+            android:paddingLeft="10dp"
+            android:paddingTop="5dp"
+            android:paddingRight="10dp"
+            android:paddingBottom="5dp"
+            android:text="12F"
+            android:textColor="@color/black_272727"
+            android:textSize="16sp" />
+
+    </RelativeLayout>
+
+    <androidx.appcompat.widget.LinearLayoutCompat
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@color/grey_50"
+        android:orientation="vertical"
+        android:paddingTop="20dp"
+        android:paddingBottom="20dp">
+
+        <androidx.core.widget.NestedScrollView
+            android:layout_width="match_parent"
+            android:layout_height="100dp">
+
+            <TextView
+                android:id="@+id/spaceName"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:paddingLeft="16dp"
+                android:paddingRight="16dp"
+                android:text=""
+                android:textColor="@color/black_272727"
+                android:textSize="13sp" />
+        </androidx.core.widget.NestedScrollView>
+
+
+        <androidx.appcompat.widget.LinearLayoutCompat
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="20dp"
+            android:layout_marginTop="20dp"
+            android:layout_marginRight="20dp"
+            android:orientation="horizontal">
+
+            <TextView
+                android:id="@+id/close"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:background="@drawable/bg_grey_e6e6e6"
+                android:gravity="center"
+                android:paddingTop="8dp"
+                android:paddingBottom="8dp"
+                android:text="关闭"
+                android:textColor="@color/black_272727"
+                android:textSize="16sp" />
+
+            <TextView
+                android:id="@+id/save"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="36dp"
+                android:layout_weight="1"
+                android:background="@drawable/bg_blue_3bacb2"
+                android:gravity="center"
+                android:paddingTop="8dp"
+                android:paddingBottom="8dp"
+                android:text="保存"
+                android:textColor="@color/white_ffffff"
+                android:textSize="16sp" />
+        </androidx.appcompat.widget.LinearLayoutCompat>
+    </androidx.appcompat.widget.LinearLayoutCompat>
+</LinearLayout>

+ 27 - 2
demo/src/main/res/layout/activity_poc.xml

@@ -136,10 +136,35 @@
         android:textSize="18sp"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0.498"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintVertical_bias="0.38" />
+        app:layout_constraintVertical_bias="0.544" />
+
+    <Button
+        android:id="@+id/space3DBtn"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="空间3D"
+        android:textSize="18sp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.222"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintVertical_bias="0.393" />
+
+    <Button
+        android:id="@+id/scene3DBtn"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="勘测3D"
+        android:textSize="18sp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.78"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintVertical_bias="0.393" />
 
     <Button
         android:id="@+id/configBtn"

+ 10 - 0
demo/src/main/res/layout/activity_scene3_dactivity.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<WebView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/webview"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".activities.Space3DActivity">
+
+</WebView>

+ 10 - 0
demo/src/main/res/layout/activity_space3_dactivity.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<WebView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/webview"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".activities.Space3DActivity">
+
+</WebView>

+ 30 - 9
demo/src/main/res/layout/dialog_list_choice.xml

@@ -16,16 +16,37 @@
         android:gravity="center_horizontal"
         android:orientation="vertical">
 
-        <TextView
-            android:id="@+id/title"
+        <RelativeLayout
             android:layout_width="match_parent"
-            android:layout_height="55dp"
-            android:background="@drawable/common_line_ffffff_single_all"
-            android:gravity="center"
-            android:paddingLeft="10dp"
-            android:text="请选择"
-            android:textColor="@color/gray_a6a6a6"
-            android:textSize="15sp" />
+            android:layout_height="55dp">
+
+            <TextView
+                android:id="@+id/title"
+                android:layout_width="match_parent"
+                android:layout_height="55dp"
+                android:background="@drawable/common_line_ffffff_single_all"
+                android:gravity="center"
+                android:paddingLeft="10dp"
+                android:text="请选择"
+                android:textColor="@color/gray_a6a6a6"
+                android:textSize="15sp" />
+
+            <TextView
+                android:id="@+id/chooseSpace"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentRight="true"
+                android:layout_centerVertical="true"
+                android:layout_marginRight="16dp"
+                android:background="@drawable/bg_gray_f2f3f6"
+                android:paddingLeft="6dp"
+                android:paddingTop="5dp"
+                android:paddingRight="6dp"
+                android:paddingBottom="5dp"
+                android:text="平面图选择"
+                android:textColor="@color/black_272727"
+                android:visibility="gone" />
+        </RelativeLayout>
 
         <LinearLayout
             android:id="@+id/search_linear"