bx-865-apps #1

Merged
ksenia_mikhailova merged 140 commits from bx-865-apps into main 2024-06-27 15:03:27 +03:00
11 changed files with 353 additions and 119 deletions
Showing only changes of commit e2b407678c - Show all commits

View File

@ -1533,6 +1533,54 @@
"detail": "django.db", "detail": "django.db",
"documentation": {} "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", "label": "models",
"importPath": "django.db", "importPath": "django.db",
@ -8242,6 +8290,33 @@
"detail": "back.api.migrations.0001_initial", "detail": "back.api.migrations.0001_initial",
"documentation": {} "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", "label": "ApiConfig",
"kind": 6, "kind": 6,
@ -8256,7 +8331,7 @@
"kind": 6, "kind": 6,
"importPath": "back.api.models", "importPath": "back.api.models",
"description": "back.api.models", "description": "back.api.models",
"peekOfCode": "class Product(models.Model):\n title = models.CharField(max_length=100)\n description = models.TextField(default=None, null=True)\n model3d = models.FileField(\n default=None, blank=True, null=True, upload_to=\"files\"\n )\n image1 = models.ImageField(\n default=None, blank=True, null=True, upload_to=\"files\"\n )\n image2 = models.ImageField(", "peekOfCode": "class Product(models.Model):\n title = models.CharField(max_length=100)\n description = models.TextField(default=None, null=True)\n model3d = models.FileField(default=None, blank=True, null=True, upload_to=\"files\")\n image1 = models.ImageField(default=None, blank=True, null=True, upload_to=\"files\")\n image2 = models.ImageField(default=None, blank=True, null=True, upload_to=\"files\")\n image3 = models.ImageField(default=None, blank=True, null=True, upload_to=\"files\")\n def __str__(self):\n return self.title\nclass Floorplan(models.Model):",
"detail": "back.api.models", "detail": "back.api.models",
"documentation": {} "documentation": {}
}, },
@ -8265,7 +8340,7 @@
"kind": 6, "kind": 6,
"importPath": "back.api.models", "importPath": "back.api.models",
"description": "back.api.models", "description": "back.api.models",
"peekOfCode": "class Floorplan(models.Model):\n title = models.CharField(max_length=200)\n np_field = models.TextField()", "peekOfCode": "class Floorplan(models.Model):\n title = models.CharField(max_length=200)\n np_field = models.TextField()\n d_size = models.IntegerField(null=True, blank=True)\n d_border = models.IntegerField(null=True, blank=True)\n paths = models.TextField()",
"detail": "back.api.models", "detail": "back.api.models",
"documentation": {} "documentation": {}
}, },
@ -8283,7 +8358,25 @@
"kind": 6, "kind": 6,
"importPath": "back.api.serializers", "importPath": "back.api.serializers",
"description": "back.api.serializers", "description": "back.api.serializers",
"peekOfCode": "class FloorplanSerializer(serializers.Serializer):\n title = serializers.CharField(max_length=200)\n np_field = serializers.CharField()\n def create(self,validated_data):\n return Floorplan.objects.create(**validated_data)", "peekOfCode": "class FloorplanSerializer(serializers.ModelSerializer):\n class Meta:\n model = Floorplan\n fields = [\n \"id\",\n \"title\",\n \"np_field\",\n \"d_border\",\n \"d_size\",\n \"paths\"",
"detail": "back.api.serializers",
"documentation": {}
},
{
"label": "FloorplanListSerializer",
"kind": 6,
"importPath": "back.api.serializers",
"description": "back.api.serializers",
"peekOfCode": "class FloorplanListSerializer(serializers.ModelSerializer):\n class Meta:\n model = Floorplan\n fields = [\n \"id\",\n \"title\",\n ]",
"detail": "back.api.serializers",
"documentation": {}
},
{
"label": "logger",
"kind": 5,
"importPath": "back.api.serializers",
"description": "back.api.serializers",
"peekOfCode": "logger = logging.getLogger(\"root\")\nclass ProductSerializer(serializers.HyperlinkedModelSerializer):\n class Meta:\n model = Product\n fields = [\n \"id\",\n \"title\",\n \"description\",\n \"model3d\",\n \"image1\",",
"detail": "back.api.serializers", "detail": "back.api.serializers",
"documentation": {} "documentation": {}
}, },
@ -8319,7 +8412,7 @@
"kind": 2, "kind": 2,
"importPath": "back.api.tracer", "importPath": "back.api.tracer",
"description": "back.api.tracer", "description": "back.api.tracer",
"peekOfCode": "def parse_image(img):\n (img_h, img_w) = img.shape[:2]\n t = 1200\n w = t\n h = int((img_h / img_w) * t)\n img = cv2.resize(img, (w, h))\n gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n gray = 255 - gray\n gray = cv2.threshold(gray, 250, 255, cv2.THRESH_BINARY)[1]\n gray = cv2.blur(gray, (10, 5))", "peekOfCode": "def parse_image(img):\n (img_h, img_w) = img.shape[:2]\n t = 1920\n w = t\n h = int((img_h / img_w) * t)\n img = cv2.resize(img, (w, h))\n gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n gray = 255 - gray\n gray = cv2.threshold(gray, 250, 255, cv2.THRESH_BINARY)[1]\n gray = cv2.blur(gray, (10, 5))",
"detail": "back.api.tracer", "detail": "back.api.tracer",
"documentation": {} "documentation": {}
}, },
@ -8337,7 +8430,7 @@
"kind": 6, "kind": 6,
"importPath": "back.api.views", "importPath": "back.api.views",
"description": "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={\"title\": file.name, \"np_field\": res[\"b64\"].decode()}\n )", "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,",
"detail": "back.api.views", "detail": "back.api.views",
"documentation": {} "documentation": {}
}, },
@ -8553,7 +8646,7 @@
"kind": 5, "kind": 5,
"importPath": "back.back.urls", "importPath": "back.back.urls",
"description": "back.back.urls", "description": "back.back.urls",
"peekOfCode": "urlpatterns = [\n path(\"admin/\", admin.site.urls),\n path(\"api/products\", csrf_exempt(views.Products.as_view())),\n path(\"api/floorplan\", csrf_exempt(views.FloorplanView.as_view())),\n] + static('/files', document_root='files')", "peekOfCode": "urlpatterns = [\n path(\"admin/\", admin.site.urls),\n path(\"api/products\", csrf_exempt(views.Products.as_view())),\n path(\"api/floorplan/\", csrf_exempt(views.FloorplanView.as_view())),\n path(\"api/floorplan/<str:id>\", csrf_exempt(views.FloorplanView.as_view())),\n] + static('/files', document_root='files')",
"detail": "back.back.urls", "detail": "back.back.urls",
"documentation": {} "documentation": {}
}, },

View File

@ -33,3 +33,6 @@
@apply bg-surface-100 dark:bg-[rgba(255,255,255,0.03)] @apply bg-surface-100 dark:bg-[rgba(255,255,255,0.03)]
} }
[data-pc-section="list"] {
@apply bg-slate-50
}

View File

@ -1,5 +1,5 @@
export function* chunks(arr: any, n: number) { export function* chunks<T>(arr: T[], n: number): Generator<T[], void> {
for (let i = 0; i < arr.length; i += n) { for (let i = 0; i < arr.length; i += n) {
yield arr.slice(i, i + n); yield arr.slice(i, i + n);
} }
} }

View File

@ -1,16 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import type { FileUploadUploadEvent } from '~/node_modules/primevue/fileupload/FileUpload.d.ts' import type { FileUploadUploadEvent } from '~/node_modules/primevue/fileupload/FileUpload.d.ts'
import PF, { Grid } from 'pathfinding' import PF, { Grid } from 'pathfinding'
import { chunks } from '~/helpers';
interface SvgContext {
array: number[][],
paths: string[],
width: number,
height: number
}
const config = useRuntimeConfig() const config = useRuntimeConfig()
const plan: Ref<SvgContext | {}> = useState('plan', () => ({})); const point_array = ref<number[][]>()
const paths_array = ref<{ path: string, unwalkable: boolean, x: number, y: number }[]>()
const loading = ref<boolean>(false) const loading = ref<boolean>(false)
const canvasElement: Ref<HTMLCanvasElement | undefined> = ref(); const canvasElement: Ref<HTMLCanvasElement | undefined> = ref();
@ -21,7 +16,14 @@ const startPoint = ref<number[]>()
const endPoint = ref<number[]>() const endPoint = ref<number[]>()
const startToEndPath = ref() const startToEndPath = ref()
const chunkSize = 2 const selectFile = ref()
const loadingFile = ref(false)
const files = ref([])
const cw = 1920
const ch = 800
const nextFrame = () => new Promise(resolve => requestAnimationFrame(resolve));
const beforeUpload = () => { const beforeUpload = () => {
loading.value = true loading.value = true
@ -30,91 +32,182 @@ const beforeUpload = () => {
const onUpload = (event: FileUploadUploadEvent) => { const onUpload = (event: FileUploadUploadEvent) => {
try { try {
const data = JSON.parse(event.xhr.response) const data = JSON.parse(event.xhr.response)
plan.value = data.response point_array.value = data.response.np_field
paths_array.value = sampling_data(data.response.np_field, 8, 20)
newDraw() newDraw()
loading.value = false
} catch (error) { } catch (error) {
console.log(error) console.log(error)
loading.value = false
} }
} }
const selectFileEvent = async () => {
loadingFile.value = true
try {
const res = await fetch(`${config.public.apiBase}/api/floorplan/${selectFile.value}`)
const data = await res.json()
point_array.value = data.np_field
paths_array.value = sampling_data(data.np_field, 8, 20)
const newDraw = () => { newDraw()
} catch (error) {
console.log(error)
}
loadingFile.value = false
}
const sampling_data = (np_field: number[][], chunkSize: number, threshold: number) => {
const prepared_array = [...chunks(np_field, chunkSize)].map(line => {
const line_data = [] as any[][]
line.map((item: any) => [...chunks(item, chunkSize)]).map((item) => {
item.map((one_line, k) => {
if (!line_data[k]) line_data[k] = []
line_data[k].push(...one_line)
})
})
return line_data.map(el => {
return el.filter(e => e > 0).length > threshold ? 1 : 0
})
});
const res: any[] = []
prepared_array.forEach((line, indexY) => {
line.forEach((point, indexX) => {
const targetX = indexX * chunkSize
const targetY = indexY * chunkSize
res.push({
path: `M${targetX} ${targetY} ${targetX + chunkSize} ${targetY} ${targetX + chunkSize} ${targetY + chunkSize} ${targetX} ${targetY + chunkSize}Z`,
unwalkable: !!point,
x: indexX,
y: indexY,
})
})
})
return res
}
const newDraw = async () => {
startPoint.value = undefined startPoint.value = undefined
endPoint.value = undefined endPoint.value = undefined
startToEndPath.value = undefined startToEndPath.value = undefined
context.value = canvasElement.value?.getContext('2d') || undefined; context.value = canvasElement.value?.getContext('2d') || undefined;
const lines = (plan.value as SvgContext).array const lines = point_array.value
lines.forEach((line, indexY) => { if (!lines) return;
line.forEach((point, indexX) => {
if (canvasElement.value && context.value) {
context.value.fillStyle = point > 0 ? 'red' : 'WHITE'
context.value.fillRect(indexX, indexY, 1, 1)
}
})
});
// const t = [...chunks(lines, chunkSize)].map(y => y.map(x => x.some(i => i > 0) > 0 ? 1 : 0)) context.value?.clearRect(0, 0, cw, ch)
// console.log(t) await nextFrame()
grid.value = new PF.Grid((plan.value as SvgContext).array.map(y => y.map(x => x > 0 ? 1 : 0))) for (let indexY = 0; indexY < lines.length; indexY++) {
const line = lines[indexY];
const drawLine = () => {
line.forEach((point, indexX) => {
if (canvasElement.value && context.value && point > 0) {
context.value.fillStyle = 'crimson'
context.value.fillRect(indexX, indexY, 1, 1)
}
})
}
drawLine()
await nextFrame()
}
grid.value = new PF.Grid(lines.map(y => y.map(x => x > 0 ? 1 : 0)))
} }
const setPoint = (event: MouseEvent) => {
const toggleBlock = (name: string) => {
if (openBlocks.value.includes(name)) {
openBlocks.value.splice(openBlocks.value.indexOf(name), 1)
} else {
openBlocks.value.push(name)
}
}
const isBlockOpen = (name: string) => {
return openBlocks.value.includes(name)
}
const openBlocks = ref<string[]>([])
const fileBtnClick = async () => {
if (isBlockOpen('upload_file')) {
await loadFiles()
}
toggleBlock('upload_file')
}
const loadFiles = async () => {
try { try {
if (!event.currentTarget) return loadingFile.value = true
const target = (<HTMLCanvasElement>event.currentTarget) const res = await fetch(`${config.public.apiBase}/api/floorplan/`)
const bound = target.getBoundingClientRect() const data = await res.json()
files.value = data
const targetX = event.x - bound.x
const targetY = event.y - bound.y
const ctx = (context.value as CanvasRenderingContext2D)
if (!startPoint.value) {
startPoint.value = [targetX, targetY]
ctx.fillStyle = 'rgb(0,255,0,0.75)';
ctx.beginPath();
ctx.arc(targetX, targetY, 10, 0, 2 * Math.PI);
ctx.fill();
} else
if (!endPoint.value) {
endPoint.value = [targetX, targetY]
ctx.fillStyle = 'rgb(0,0,255,0.75)';
ctx.beginPath();
ctx.arc(targetX, targetY, 10, 0, 2 * Math.PI);
ctx.fill();
const finder = new PF.DijkstraFinder();
startToEndPath.value = finder.findPath(
Math.round(startPoint.value[0]),
Math.round(startPoint.value[1]),
Math.round(endPoint.value[0]),
Math.round(endPoint.value[1]),
(grid.value as Grid)
);
startToEndPath.value.forEach((element: number[]) => {
ctx.fillRect(element[0], element[1], 1, 1)
});
} else {
newDraw()
}
} catch (error) { } catch (error) {
console.log(error) console.log(error)
} }
loadingFile.value = false
} }
onMounted(async () => {
await loadFiles()
})
</script> </script>
<template> <template>
<div class="flex flex-col gap-4"> <div class="flex flex-col gap-4">
<Panel header="Загрузка файла"> <Panel header="Выбор пресета">
<FileUpload mode="basic" name="demo" :url="`${config.public.apiBase}/api/floorplan`" accept="image/*" <div class="flex align-center gap-2">
<Dropdown v-model="selectFile" placeholder="Выберите файл" :options="files" optionLabel="title"
optionValue="id" :loading="loadingFile" :disabled="!files.length || loadingFile"
@change="selectFileEvent" />
<Button @click="fileBtnClick()">
<span style="display: contents;" v-if="isBlockOpen('upload_file')">
Выбрать план из загруженных
</span>
<span style="display: contents;" v-else>
Загрузить новый план
</span>
</Button>
</div>
</Panel>
<Panel header="Загрузка файла" v-if="isBlockOpen('upload_file')">
<FileUpload mode="basic" name="demo" :url="`${config.public.apiBase}/api/floorplan/`" accept="image/*"
:maxFileSize="10000000" @upload="onUpload" @before-upload="beforeUpload" :auto="true" :maxFileSize="10000000" @upload="onUpload" @before-upload="beforeUpload" :auto="true"
chooseLabel="Выберите файл" :disabled="loading" /> chooseLabel="Выберите файл" :disabled="loading" />
</Panel> </Panel>
<Panel :header="loading ? `Идет отрисовка` : `Отрисовка из массива значений`">
<canvas ref="canvasElement" :width="1200" height="400" @click="setPoint"></canvas> <Panel :header="loading ? `Идет отрисовка` : `Обработанный план здания`">
<div style=" max-width: 100%; overflow: auto; position: relative;">
<canvas ref="canvasElement" :width="cw" :height="ch" style="position: absolute; z-index: -1;"></canvas>
<svg ref="svgElement" :width="cw" :height="ch">
<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>
</div>
</Panel> </Panel>
</div> </div>
</template> </template>
<style scoped>
svg path {
fill: transparent
}
svg path:hover {
fill: red
}
svg path.unwalkable {
fill: rgba(0, 0, 0, 0.5);
}
svg path.endPoint {
fill: blue;
}
svg path.startPoint {
fill: lawngreen;
}
svg path.pathPoint {
fill: gold;
}
</style>

View File

@ -1,27 +1,23 @@
from django.db import models from django.db import models
import json
# Create your models here. # Create your models here.
class Product(models.Model): class Product(models.Model):
title = models.CharField(max_length=100) title = models.CharField(max_length=100)
description = models.TextField(default=None, null=True) description = models.TextField(default=None, null=True)
model3d = models.FileField( model3d = models.FileField(default=None, blank=True, null=True, upload_to="files")
default=None, blank=True, null=True, upload_to="files" image1 = models.ImageField(default=None, blank=True, null=True, upload_to="files")
) image2 = models.ImageField(default=None, blank=True, null=True, upload_to="files")
image1 = models.ImageField( image3 = models.ImageField(default=None, blank=True, null=True, upload_to="files")
default=None, blank=True, null=True, upload_to="files"
)
image2 = models.ImageField(
default=None, blank=True, null=True, upload_to="files"
)
image3 = models.ImageField(
default=None, blank=True, null=True, upload_to="files"
)
def __str__(self): def __str__(self):
return self.title return self.title
class Floorplan(models.Model): class Floorplan(models.Model):
title = models.CharField(max_length=200) title = models.CharField(max_length=200)
np_field = models.TextField() np_field = models.TextField()
d_size = models.IntegerField(null=True, blank=True)
d_border = models.IntegerField(null=True, blank=True)
paths = models.TextField()

View File

@ -1,6 +1,8 @@
from rest_framework import routers, serializers, viewsets from rest_framework import routers, serializers, viewsets
from .models import Product, Floorplan from .models import Product, Floorplan
import logging
logger = logging.getLogger("root")
class ProductSerializer(serializers.HyperlinkedModelSerializer): class ProductSerializer(serializers.HyperlinkedModelSerializer):
class Meta: class Meta:
@ -16,9 +18,22 @@ class ProductSerializer(serializers.HyperlinkedModelSerializer):
] ]
class FloorplanSerializer(serializers.Serializer): class FloorplanSerializer(serializers.ModelSerializer):
title = serializers.CharField(max_length=200) class Meta:
np_field = serializers.CharField() model = Floorplan
fields = [
def create(self,validated_data): "id",
return Floorplan.objects.create(**validated_data) "title",
"np_field",
"d_border",
"d_size",
"paths"
]
class FloorplanListSerializer(serializers.ModelSerializer):
class Meta:
model = Floorplan
fields = [
"id",
"title",
]

View File

@ -31,7 +31,7 @@ def read_image(content: bytes) -> np.ndarray:
def parse_image(img): def parse_image(img):
(img_h, img_w) = img.shape[:2] (img_h, img_w) = img.shape[:2]
t = 1200 t = 1920
w = t w = t
h = int((img_h / img_w) * t) h = int((img_h / img_w) * t)
img = cv2.resize(img, (w, h)) img = cv2.resize(img, (w, h))

View File

@ -1,10 +1,10 @@
import json
from rest_framework.parsers import JSONParser, MultiPartParser from rest_framework.parsers import JSONParser, MultiPartParser
from rest_framework.views import APIView from rest_framework.views import APIView
from django.http import JsonResponse from django.http import JsonResponse
from api.tracer import parse_image, read_image, numpy_zip_str_to_arr from api.tracer import parse_image, read_image, numpy_zip_str_to_arr
from .serializers import FloorplanSerializer, ProductSerializer from .serializers import FloorplanSerializer, FloorplanListSerializer, ProductSerializer
from .models import Floorplan, Product from .models import Floorplan, Product
import logging import logging
@ -38,26 +38,43 @@ class FloorplanView(APIView):
logger.info(file.__dict__) logger.info(file.__dict__)
res = parse_image(read_image(file.read())) res = parse_image(read_image(file.read()))
serializer = FloorplanSerializer( serializer = FloorplanSerializer(
data={"title": file.name, "np_field": res["b64"].decode()} data={
"title": file.name,
"np_field": res["b64"].decode(),
"paths": json.dumps(res["paths"]),
}
) )
logger.info(res["b64"])
if serializer.is_valid(): if serializer.is_valid():
serializer.save() serializer.save()
return JsonResponse( return JsonResponse(
data={"response": {"array": res["array"]}}, status=201 data={
"response": {
"np_field": res["array"],
"paths": res["paths"],
}
},
status=201,
) )
else:
logger.info(serializer.errors)
return JsonResponse(serializer.errors, status=500) return JsonResponse(serializer.errors, status=500)
except Exception as e: except Exception as e:
logger.error(e) logger.error(e)
raise e raise e
def get(self, request): def get(self, request, id=None):
try: try:
item = Floorplan.objects.last() if id is not None:
serializer = FloorplanSerializer(item, many=False) item = Floorplan.objects.get(id=id)
data = serializer.data serializer = FloorplanSerializer(item, many=False)
data["np_field"] = numpy_zip_str_to_arr(data["np_field"]) data = serializer.data
return JsonResponse(data, safe=False) data["np_field"] = numpy_zip_str_to_arr(data["np_field"])
return JsonResponse(data, safe=False)
else:
items = Floorplan.objects.only("id", "title").all()
serializer = FloorplanListSerializer(items, many=True)
return JsonResponse(serializer.data, safe=False)
except Exception as e: except Exception as e:
logger.error(e) logger.error(e)
raise e raise e

View File

@ -23,5 +23,6 @@ from django.views.decorators.csrf import csrf_exempt
urlpatterns = [ urlpatterns = [
path("admin/", admin.site.urls), path("admin/", admin.site.urls),
path("api/products", csrf_exempt(views.Products.as_view())), path("api/products", csrf_exempt(views.Products.as_view())),
path("api/floorplan", csrf_exempt(views.FloorplanView.as_view())), path("api/floorplan/", csrf_exempt(views.FloorplanView.as_view())),
path("api/floorplan/<str:id>", csrf_exempt(views.FloorplanView.as_view())),
] + static('/files', document_root='files') ] + static('/files', document_root='files')

View File

@ -12,7 +12,7 @@ const canvasElement = ref();
const context = ref(); const context = ref();
const grid = ref<Grid>() const grid = ref<Grid>()
const startPoint = ref<{ x: number, y: number }>({ x: 27, y: 38 }) const startPoint = ref<{ x: number, y: number }>({ x: 25, y: 40 })
const endPoint = ref<{ x: number, y: number }>() const endPoint = ref<{ x: number, y: number }>()
const startToEndPath = ref() const startToEndPath = ref()
@ -30,12 +30,26 @@ const newDraw = () => {
lines.forEach((line, indexY) => { lines.forEach((line, indexY) => {
line.forEach((point, indexX) => { line.forEach((point, indexX) => {
if (canvasElement.value && context.value) { if (canvasElement.value && context.value) {
context.value.fillStyle = point > 0 ? 'red' : 'WHITE' context.value.fillStyle = point > 0 ? 'purple' : 'WHITE'
context.value.fillRect(indexX, indexY, 1, 1) context.value.fillRect(indexX, indexY, 1, 1)
} }
}) })
}); });
// if (canvasElement.value && context.value) {
// context.value.clearRect(0, 0, canvasElement.value.width, canvasElement.value.height);
// if (!plan.value.hasOwnProperty('paths')) return
// (plan.value).paths.forEach((path: string) => {
// if (!context.value) return
// context.value.fillStyle = 'rgba(255, 0, 255, 0.25)'
// context.value.fill(new Path2D(path));
// context.value.strokeStyle = 'blue'
// context.value.stroke(new Path2D(path));
// });
// }
const quantum_lines = plan.prepared_array const quantum_lines = plan.prepared_array
quantum_lines.forEach((line, indexY) => { quantum_lines.forEach((line, indexY) => {
line.forEach((point, indexX) => { line.forEach((point, indexX) => {
@ -55,7 +69,7 @@ const newDraw = () => {
const findPath = async () => { const findPath = async () => {
if (!endPoint.value) return if (!endPoint.value) return
const localPath = finder.findPath( const localPath = finder.findPath(
Math.round(startPoint.value.x), Math.round(startPoint.value.x),
Math.round(startPoint.value.y), Math.round(startPoint.value.y),
Math.round(endPoint.value.x), Math.round(endPoint.value.x),
@ -75,11 +89,13 @@ onMounted(async () => {
await floorplan.getData() await floorplan.getData()
newDraw() newDraw()
}) })
const cw = 1920
const ch = 800
</script> </script>
<template> <template>
<div class="container" style="display: flex; justify-content: center; align-items: center; flex-direction: column;"> <div class="container" style="display: flex; justify-content: center; align-items: center; flex-direction: column;">
<canvas ref="canvasElement" width="1200" height="600"></canvas> <canvas ref="canvasElement" :width="cw" :height="ch"></canvas>
<svg ref="svgElement" width="1200" height="600" style="position: absolute;"> <svg ref="svgElement" :width="cw" :height="ch" style="position: absolute;">
<path v-for="item in paths" :d="item.path" @click="setPointSvg(item)" :class="[ <path v-for="item in paths" :d="item.path" @click="setPointSvg(item)" :class="[
{ 'unwalkable': item.unwalkable }, { 'unwalkable': item.unwalkable },
{ 'endPoint': (endPoint && item.x == endPoint.x && item.y == endPoint.y) }, { 'endPoint': (endPoint && item.x == endPoint.x && item.y == endPoint.y) },
@ -100,7 +116,7 @@ svg path:hover {
} }
svg path.unwalkable { svg path.unwalkable {
fill: rgba(0, 0, 0, 0.5); /* fill: rgba(0, 0, 0, 0.5); */
} }
svg path.endPoint { svg path.endPoint {

View File

@ -6,7 +6,7 @@ export const useFloorplanStore = defineStore('floorplan', {
state: () => { state: () => {
return { return {
title: undefined, title: undefined,
chunkSize: 5, chunkSize: 7,
np_array: [] as number[][], np_array: [] as number[][],
prepared_array: [] as number[][] prepared_array: [] as number[][]
} }
@ -27,7 +27,7 @@ export const useFloorplanStore = defineStore('floorplan', {
}) })
}) })
return line_data.map(el => { return line_data.map(el => {
return el.filter(e => e > 0).length > 10 ? 1 : 0 return el.filter(e => e > 0).length > 20 ? 1 : 0
}) })
}); });
} catch (error) { } catch (error) {