bx-865-apps #1

Merged
ksenia_mikhailova merged 140 commits from bx-865-apps into main 2024-06-27 15:03:27 +03:00
4 changed files with 239 additions and 166 deletions
Showing only changes of commit 978800bfae - Show all commits

View File

@ -1,39 +1,4 @@
[
{
"label": "annotations",
"importPath": "__future__",
"description": "__future__",
"isExtraImport": true,
"detail": "__future__",
"documentation": {}
},
{
"label": "os",
"kind": 6,
"isExtraImport": true,
"importPath": "os",
"description": "os",
"detail": "os",
"documentation": {}
},
{
"label": "site",
"kind": 6,
"isExtraImport": true,
"importPath": "site",
"description": "site",
"detail": "site",
"documentation": {}
},
{
"label": "sys",
"kind": 6,
"isExtraImport": true,
"importPath": "sys",
"description": "sys",
"detail": "sys",
"documentation": {}
},
{
"label": "json",
"kind": 6,
@ -132,6 +97,15 @@
"detail": "gyp.common",
"documentation": {}
},
{
"label": "os",
"kind": 6,
"isExtraImport": true,
"importPath": "os",
"description": "os",
"detail": "os",
"documentation": {}
},
{
"label": "posixpath",
"kind": 6,
@ -275,6 +249,15 @@
"detail": "code",
"documentation": {}
},
{
"label": "sys",
"kind": 6,
"isExtraImport": true,
"importPath": "sys",
"description": "sys",
"detail": "sys",
"documentation": {}
},
{
"label": "hashlib",
"kind": 6,
@ -1534,6 +1517,78 @@
"detail": "time",
"documentation": {}
},
{
"label": "migrations",
"importPath": "django.db",
"description": "django.db",
"isExtraImport": true,
"detail": "django.db",
"documentation": {}
},
{
"label": "models",
"importPath": "django.db",
"description": "django.db",
"isExtraImport": true,
"detail": "django.db",
"documentation": {}
},
{
"label": "migrations",
"importPath": "django.db",
"description": "django.db",
"isExtraImport": true,
"detail": "django.db",
"documentation": {}
},
{
"label": "models",
"importPath": "django.db",
"description": "django.db",
"isExtraImport": true,
"detail": "django.db",
"documentation": {}
},
{
"label": "migrations",
"importPath": "django.db",
"description": "django.db",
"isExtraImport": true,
"detail": "django.db",
"documentation": {}
},
{
"label": "models",
"importPath": "django.db",
"description": "django.db",
"isExtraImport": true,
"detail": "django.db",
"documentation": {}
},
{
"label": "migrations",
"importPath": "django.db",
"description": "django.db",
"isExtraImport": true,
"detail": "django.db",
"documentation": {}
},
{
"label": "models",
"importPath": "django.db",
"description": "django.db",
"isExtraImport": true,
"detail": "django.db",
"documentation": {}
},
{
"label": "models",
"importPath": "django.db",
"description": "django.db",
"isExtraImport": true,
"detail": "django.db",
"documentation": {}
},
{
"label": "admin",
"importPath": "django.contrib",
@ -1558,14 +1613,6 @@
"detail": "django.apps",
"documentation": {}
},
{
"label": "models",
"importPath": "django.db",
"description": "django.db",
"isExtraImport": true,
"detail": "django.db",
"documentation": {}
},
{
"label": "routers",
"importPath": "rest_framework",
@ -1745,87 +1792,6 @@
"detail": "django.core.wsgi",
"documentation": {}
},
{
"label": "bin_dir",
"kind": 5,
"importPath": ".venv.bin.activate_this",
"description": ".venv.bin.activate_this",
"peekOfCode": "bin_dir = os.path.dirname(abs_file)\nbase = bin_dir[: -len(\"bin\") - 1] # strip away the bin part from the __file__, plus the path separator\n# prepend bin to PATH (this file is inside the bin directory)\nos.environ[\"PATH\"] = os.pathsep.join([bin_dir, *os.environ.get(\"PATH\", \"\").split(os.pathsep)])\nos.environ[\"VIRTUAL_ENV\"] = base # virtual env is right above bin directory\nos.environ[\"VIRTUAL_ENV_PROMPT\"] = \"interactive-table-py3.10\" or os.path.basename(base) # noqa: SIM222\n# add the virtual environments libraries to the host python import mechanism\nprev_length = len(sys.path)\nfor lib in \"../lib/python3.10/site-packages\".split(os.pathsep):\n path = os.path.realpath(os.path.join(bin_dir, lib))",
"detail": ".venv.bin.activate_this",
"documentation": {}
},
{
"label": "base",
"kind": 5,
"importPath": ".venv.bin.activate_this",
"description": ".venv.bin.activate_this",
"peekOfCode": "base = bin_dir[: -len(\"bin\") - 1] # strip away the bin part from the __file__, plus the path separator\n# prepend bin to PATH (this file is inside the bin directory)\nos.environ[\"PATH\"] = os.pathsep.join([bin_dir, *os.environ.get(\"PATH\", \"\").split(os.pathsep)])\nos.environ[\"VIRTUAL_ENV\"] = base # virtual env is right above bin directory\nos.environ[\"VIRTUAL_ENV_PROMPT\"] = \"interactive-table-py3.10\" or os.path.basename(base) # noqa: SIM222\n# add the virtual environments libraries to the host python import mechanism\nprev_length = len(sys.path)\nfor lib in \"../lib/python3.10/site-packages\".split(os.pathsep):\n path = os.path.realpath(os.path.join(bin_dir, lib))\n site.addsitedir(path.decode(\"utf-8\") if \"\" else path)",
"detail": ".venv.bin.activate_this",
"documentation": {}
},
{
"label": "os.environ[\"PATH\"]",
"kind": 5,
"importPath": ".venv.bin.activate_this",
"description": ".venv.bin.activate_this",
"peekOfCode": "os.environ[\"PATH\"] = os.pathsep.join([bin_dir, *os.environ.get(\"PATH\", \"\").split(os.pathsep)])\nos.environ[\"VIRTUAL_ENV\"] = base # virtual env is right above bin directory\nos.environ[\"VIRTUAL_ENV_PROMPT\"] = \"interactive-table-py3.10\" or os.path.basename(base) # noqa: SIM222\n# add the virtual environments libraries to the host python import mechanism\nprev_length = len(sys.path)\nfor lib in \"../lib/python3.10/site-packages\".split(os.pathsep):\n path = os.path.realpath(os.path.join(bin_dir, lib))\n site.addsitedir(path.decode(\"utf-8\") if \"\" else path)\nsys.path[:] = sys.path[prev_length:] + sys.path[0:prev_length]\nsys.real_prefix = sys.prefix",
"detail": ".venv.bin.activate_this",
"documentation": {}
},
{
"label": "os.environ[\"VIRTUAL_ENV\"]",
"kind": 5,
"importPath": ".venv.bin.activate_this",
"description": ".venv.bin.activate_this",
"peekOfCode": "os.environ[\"VIRTUAL_ENV\"] = base # virtual env is right above bin directory\nos.environ[\"VIRTUAL_ENV_PROMPT\"] = \"interactive-table-py3.10\" or os.path.basename(base) # noqa: SIM222\n# add the virtual environments libraries to the host python import mechanism\nprev_length = len(sys.path)\nfor lib in \"../lib/python3.10/site-packages\".split(os.pathsep):\n path = os.path.realpath(os.path.join(bin_dir, lib))\n site.addsitedir(path.decode(\"utf-8\") if \"\" else path)\nsys.path[:] = sys.path[prev_length:] + sys.path[0:prev_length]\nsys.real_prefix = sys.prefix\nsys.prefix = base",
"detail": ".venv.bin.activate_this",
"documentation": {}
},
{
"label": "os.environ[\"VIRTUAL_ENV_PROMPT\"]",
"kind": 5,
"importPath": ".venv.bin.activate_this",
"description": ".venv.bin.activate_this",
"peekOfCode": "os.environ[\"VIRTUAL_ENV_PROMPT\"] = \"interactive-table-py3.10\" or os.path.basename(base) # noqa: SIM222\n# add the virtual environments libraries to the host python import mechanism\nprev_length = len(sys.path)\nfor lib in \"../lib/python3.10/site-packages\".split(os.pathsep):\n path = os.path.realpath(os.path.join(bin_dir, lib))\n site.addsitedir(path.decode(\"utf-8\") if \"\" else path)\nsys.path[:] = sys.path[prev_length:] + sys.path[0:prev_length]\nsys.real_prefix = sys.prefix\nsys.prefix = base",
"detail": ".venv.bin.activate_this",
"documentation": {}
},
{
"label": "prev_length",
"kind": 5,
"importPath": ".venv.bin.activate_this",
"description": ".venv.bin.activate_this",
"peekOfCode": "prev_length = len(sys.path)\nfor lib in \"../lib/python3.10/site-packages\".split(os.pathsep):\n path = os.path.realpath(os.path.join(bin_dir, lib))\n site.addsitedir(path.decode(\"utf-8\") if \"\" else path)\nsys.path[:] = sys.path[prev_length:] + sys.path[0:prev_length]\nsys.real_prefix = sys.prefix\nsys.prefix = base",
"detail": ".venv.bin.activate_this",
"documentation": {}
},
{
"label": "sys.path[:]",
"kind": 5,
"importPath": ".venv.bin.activate_this",
"description": ".venv.bin.activate_this",
"peekOfCode": "sys.path[:] = sys.path[prev_length:] + sys.path[0:prev_length]\nsys.real_prefix = sys.prefix\nsys.prefix = base",
"detail": ".venv.bin.activate_this",
"documentation": {}
},
{
"label": "sys.real_prefix",
"kind": 5,
"importPath": ".venv.bin.activate_this",
"description": ".venv.bin.activate_this",
"peekOfCode": "sys.real_prefix = sys.prefix\nsys.prefix = base",
"detail": ".venv.bin.activate_this",
"documentation": {}
},
{
"label": "sys.prefix",
"kind": 5,
"importPath": ".venv.bin.activate_this",
"description": ".venv.bin.activate_this",
"peekOfCode": "sys.prefix = base",
"detail": ".venv.bin.activate_this",
"documentation": {}
},
{
"label": "_Known",
"kind": 6,
@ -8315,6 +8281,42 @@
"detail": "admin_front.node_modules.node-gyp.gyp.test_gyp",
"documentation": {}
},
{
"label": "Migration",
"kind": 6,
"importPath": "back.api.migrations.0001_initial",
"description": "back.api.migrations.0001_initial",
"peekOfCode": "class Migration(migrations.Migration):\n initial = True\n dependencies = [\n ]\n operations = [\n migrations.CreateModel(\n name='Floorplan',\n fields=[\n ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),\n ('title', models.CharField(max_length=200)),",
"detail": "back.api.migrations.0001_initial",
"documentation": {}
},
{
"label": "Migration",
"kind": 6,
"importPath": "back.api.migrations.0002_floorplan_d_border_floorplan_d_size_floorplan_paths",
"description": "back.api.migrations.0002_floorplan_d_border_floorplan_d_size_floorplan_paths",
"peekOfCode": "class Migration(migrations.Migration):\n dependencies = [\n ('api', '0001_initial'),\n ]\n operations = [\n migrations.AddField(\n model_name='floorplan',\n name='d_border',\n field=models.IntegerField(default=1),\n preserve_default=False,",
"detail": "back.api.migrations.0002_floorplan_d_border_floorplan_d_size_floorplan_paths",
"documentation": {}
},
{
"label": "Migration",
"kind": 6,
"importPath": "back.api.migrations.0003_alter_floorplan_paths",
"description": "back.api.migrations.0003_alter_floorplan_paths",
"peekOfCode": "class Migration(migrations.Migration):\n dependencies = [\n ('api', '0002_floorplan_d_border_floorplan_d_size_floorplan_paths'),\n ]\n operations = [\n migrations.AlterField(\n model_name='floorplan',\n name='paths',\n field=models.TextField(),\n ),",
"detail": "back.api.migrations.0003_alter_floorplan_paths",
"documentation": {}
},
{
"label": "Migration",
"kind": 6,
"importPath": "back.api.migrations.0004_alter_floorplan_d_border_alter_floorplan_d_size",
"description": "back.api.migrations.0004_alter_floorplan_d_border_alter_floorplan_d_size",
"peekOfCode": "class Migration(migrations.Migration):\n dependencies = [\n ('api', '0003_alter_floorplan_paths'),\n ]\n operations = [\n migrations.AlterField(\n model_name='floorplan',\n name='d_border',\n field=models.IntegerField(blank=True, null=True),\n ),",
"detail": "back.api.migrations.0004_alter_floorplan_d_border_alter_floorplan_d_size",
"documentation": {}
},
{
"label": "ApiConfig",
"kind": 6,
@ -8428,7 +8430,7 @@
"kind": 6,
"importPath": "back.api.views",
"description": "back.api.views",
"peekOfCode": "class FloorplanView(APIView):\n parser_classes = (MultiPartParser,)\n def post(self, request):\n try:\n file = request.FILES[\"demo\"]\n logger.info(file.__dict__)\n res = parse_image(read_image(file.read()))\n serializer = FloorplanSerializer(\n data={\n \"title\": file.name,",
"peekOfCode": "class FloorplanView(APIView):\n parser_classes = (\n MultiPartParser,\n JSONParser,\n )\n def post(self, request):\n try:\n file = request.FILES[\"demo\"]\n logger.info(file.__dict__)\n res = parse_image(read_image(file.read()))",
"detail": "back.api.views",
"documentation": {}
},

View File

@ -5,14 +5,20 @@ import * as d3 from "d3";
const point_array = useState<number[][] | undefined>('point_array', () => undefined)
const chunk_size = useState<number>('chunk_size', () => 8)
const threshold = useState<number>('threshold', () => 20)
const grid_redraw = useState<boolean>('grid_redraw', () => false)
const active_point = useState<{ x: number, y: number } | undefined>('active_point', () => undefined)
const target_points = useState<{ x: number, y: number, type: string }[]>('target_points', () => [])
const paths_array = ref<{ path: string, unwalkable: boolean, x: number, y: number }[]>()
const props = defineProps(['cw', 'ch'])
const d3svg = ref()
const setActivePoint = (item: { x: number, y: number }) => {
active_point.value = { x: item.x, y: item.y }
}
const sampling_data = () => {
grid_redraw.value = true
const points = point_array.value
const chunk = chunk_size.value
if (!points) return
@ -28,6 +34,7 @@ const sampling_data = () => {
return el.filter(e => e > 0).length > threshold.value ? 1 : 0
})
});
const res: any[] = []
prepared_array.forEach((line, indexY) => {
line.forEach((point, indexX) => {
@ -48,33 +55,46 @@ const sampling_data = () => {
// svg.selectAll("path").remove();
const path_elements = svg.selectAll("path")
paths_array.value.forEach((element, i) => {
if (!d3.select(path_elements.nodes()[i]).empty()) {
console.log(`update ${i}`)
d3.select(path_elements.nodes()[i])
.transition()
.duration(300)
.attr('d', element.path)
.attr('class', element.unwalkable ? 'unwalkable' : 'walkable')
paths_array.value.forEach(async (element, i) => {
let _class = '';
if (element.unwalkable) {
_class += ' unwalkable'
} else {
console.log(`add ${i}`)
_class += ' walkable'
}
if (target_points.value.find(el => el.x == element.x && el.y === element.y)) {
_class += ' active'
}
const clickFunk = () => setActivePoint({ x: element.x, y: element.y })
if (path_elements.nodes()[i]) {
// console.log(`update ${i}`)
d3.select(path_elements.nodes()[i])
// .transition()
// .duration(300)
.attr('d', element.path)
.attr('class', _class)
.on('click', clickFunk)
} else {
// console.log(`add${i}`)
svg.append("path")
.attr('d', element.path)
.attr('class', element.unwalkable ? 'unwalkable' : 'walkable')
.attr('class', _class)
.on('click', clickFunk)
}
});
console.timeEnd('redraw D3')
grid_redraw.value = false
}
watch(point_array, () => {
console.log('point_array')
sampling_data()
})
}, { deep: true })
watch(target_points, () => {
sampling_data()
}, { deep: true })
watch(chunk_size, () => {
console.log('chunk size')
sampling_data()
})
watch(threshold, () => {
console.log('threshold')
sampling_data()
})
onMounted(() => {
@ -83,15 +103,6 @@ onMounted(() => {
</script>
<template>
<div>
<svg :width="props.cw" :height="props.ch" v-if="false">
<path v-for="item in paths_array" :d="item.path" :class="[
{ 'unwalkable': item.unwalkable },
// { 'endPoint': (endPoint && item.x == endPoint.x && item.y == endPoint.y) },
// { 'startPoint': (startPoint && item.x == startPoint.x && item.y == startPoint.y) },
// { 'pathPoint': (startToEndPath && startToEndPath.find((el: number[]) => el[0] == item.x && el[1] == item.y)) },
]">
</path>
</svg>
<svg :width="props.cw" :height="props.ch" ref="d3svg" id="d3svg"></svg>
</div>
</template>
@ -102,10 +113,6 @@ svg path {
stroke: rgba(70, 70, 0, 0.1);
}
svg path:hover {
fill: red
}
svg path.unwalkable {
fill: rgba(70, 70, 0, 0.5);
}
@ -114,11 +121,16 @@ svg path.endPoint {
fill: blue;
}
svg path.startPoint {
svg path.active {
fill: lawngreen;
}
svg path.pathPoint {
fill: gold;
svg path.active {
/* fill: gold; */
}
svg path:hover {
fill: rgba(255, 0, 0, 0.5);
}
</style>

View File

@ -1,12 +1,14 @@
<script setup lang="ts">
import type { FileUploadUploadEvent } from '~/node_modules/primevue/fileupload/FileUpload.d.ts'
import PF, { Grid } from 'pathfinding'
import { chunks } from '~/helpers';
import { Grid } from 'pathfinding'
const config = useRuntimeConfig()
const point_array = useState('point_array', () => [[]])
const chunk_size = useState('chunk_size', () => 8)
const threshold = useState('threshold', () => 20)
const grid_redraw = useState<boolean>('grid_redraw', () => false)
const active_point = useState<{ x: number, y: number } | undefined>('active_point', () => undefined)
const target_points = useState<{ x: number, y: number, type: string }[]>('target_points', () => [])
const loading = ref<boolean>(false)
@ -27,6 +29,8 @@ const title = ref()
const dataToState = (data: any) => {
point_array.value = data.np_field
title.value = data.title
if (data.d_size) chunk_size.value = data.d_size
if (data.d_border) threshold.value = data.d_border
}
const onUpload = (event: FileUploadUploadEvent) => {
@ -84,6 +88,7 @@ const updateValues = async () => {
const res = await fetch(`${config.public.apiBase}/api/floorplan/${selectFile.value}`, {
method: 'PATCH',
headers: {
'Accept': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify({
@ -94,9 +99,36 @@ const updateValues = async () => {
})
const data = await res.json()
}
const target_array = ref<{ type: string, title: string, points?: { x: number, y: number } }[]>([])
const target_type = ref()
const addTargetType = (name: string) => {
target_type.value = name
}
onMounted(async () => {
await loadFiles()
})
watch(grid_redraw, () => {
loading.value = grid_redraw.value
})
watch(active_point, () => {
if (target_type.value === 'start') {
if (!active_point.value) return
const t_index = target_array.value.findIndex(el => el.type == 'start')
if (t_index !== -1) target_array.value.splice(t_index, 1)
const t = ({ type: 'start', title: 'home', points: active_point.value })
const t_state_index = target_points.value.findIndex(el => el.type == 'start')
if (t_state_index !== -1) target_points.value.splice(t_state_index, 1)
const t_state = ({ type: 'start', x: active_point.value.x, y: active_point.value.y })
target_array.value.push(t)
target_points.value.push(t_state)
}
})
</script>
<template>
<div class="flex flex-col gap-4">
@ -105,7 +137,7 @@ onMounted(async () => {
<Dropdown v-model="selectFile" placeholder="Выберите файл" :options="files" optionLabel="title"
optionValue="id" :loading="loadingFile" :disabled="!files.length || loadingFile"
@change="selectFileEvent" />
<Button @click="fileBtnClick()">
<Button @click="fileBtnClick()" :disabled="loadingFile">
<span style="display: contents;" v-if="isBlockOpen('upload_file')">
Выбрать план из загруженных
</span>
@ -121,7 +153,9 @@ onMounted(async () => {
:disabled="loading" />
</Panel>
<Panel header="Данные для работы">
<Panel header="Данные для координатной сетки">
<p>Рекомендуем использовать сетку с наиболее крупными ячейками</p>
<Divider />
<div class="flex align-middle items-end gap-2">
<div class="flex flex-col">
<label for="title">Название</label>
@ -129,17 +163,40 @@ onMounted(async () => {
</div>
<div class="flex flex-col">
<label for="chunk">Значение дискретизации</label>
<InputNumber id="chunk" type="text" showButtons :min="0" :max="50" v-model="chunk_size" />
<InputNumber id="chunk" type="text" showButtons :min="8" :max="50" v-model="chunk_size" />
</div>
<div class="flex flex-col">
<label for="threshold">Пороговое значение</label>
<InputNumber id="threshold" type="text" showButtons :min="0" :max="chunk_size * chunk_size"
<InputNumber id="threshold" showButtons :min="0" :max="chunk_size * chunk_size" :disabled="loading"
v-model="threshold" />
</div>
<Button @click="updateValues">Сохранить данные</Button>
</div>
</Panel>
<Panel header="Данные о помещениях">
<div class="flex gap-2">
<div class="flex flex-col gap-2">
<Button @click="addTargetType('start')">{{ !target_array.filter(el => el.type == 'start').length ?
`Добавить` : 'Изменить' }}
точку старта</Button>
<Button @click="addTargetType('cabinet')">Добавить точку входа в кабинет</Button>
</div>
<div class="flex flex-col">
<span v-if="active_point">
{{ active_point }}
</span>
<ul>
<li v-for="item in target_array">
{{ item.title }}
{{ item.type }}
{{ item.points }}
</li>
</ul>
</div>
</div>
</Panel>
<Panel :header="loading ? `Идет отрисовка` : `Обработанный план здания`">
<div style=" max-width: 100%; overflow: auto; position: relative;">
<FloorplanCanvas :cw="cw" :ch="ch" />

View File

@ -30,7 +30,10 @@ class Products(APIView):
class FloorplanView(APIView):
parser_classes = (MultiPartParser,)
parser_classes = (
MultiPartParser,
JSONParser,
)
def post(self, request):
try:
@ -84,10 +87,9 @@ class FloorplanView(APIView):
if id is not None:
item = Floorplan.objects.get(id=id)
serializer = FloorplanSerializer(item, data=request.data, partial=True)
data = serializer.data
if serializer.is_valid():
serializer.save()
return JsonResponse(status=201)
return JsonResponse(serializer.data, status=201)
else:
logger.info(serializer.errors)
else: