bx-865-apps #1
|
@ -1533,6 +1533,54 @@
|
|||
"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",
|
||||
|
@ -8242,6 +8290,33 @@
|
|||
"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,
|
||||
|
@ -8256,7 +8331,7 @@
|
|||
"kind": 6,
|
||||
"importPath": "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",
|
||||
"documentation": {}
|
||||
},
|
||||
|
@ -8265,7 +8340,7 @@
|
|||
"kind": 6,
|
||||
"importPath": "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",
|
||||
"documentation": {}
|
||||
},
|
||||
|
@ -8283,7 +8358,25 @@
|
|||
"kind": 6,
|
||||
"importPath": "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",
|
||||
"documentation": {}
|
||||
},
|
||||
|
@ -8319,7 +8412,7 @@
|
|||
"kind": 2,
|
||||
"importPath": "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",
|
||||
"documentation": {}
|
||||
},
|
||||
|
@ -8337,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={\"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",
|
||||
"documentation": {}
|
||||
},
|
||||
|
@ -8553,7 +8646,7 @@
|
|||
"kind": 5,
|
||||
"importPath": "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",
|
||||
"documentation": {}
|
||||
},
|
||||
|
|
|
@ -33,3 +33,6 @@
|
|||
@apply bg-surface-100 dark:bg-[rgba(255,255,255,0.03)]
|
||||
}
|
||||
|
||||
[data-pc-section="list"] {
|
||||
@apply bg-slate-50
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
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) {
|
||||
yield arr.slice(i, i + n);
|
||||
}
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
<script setup lang="ts">
|
||||
import type { FileUploadUploadEvent } from '~/node_modules/primevue/fileupload/FileUpload.d.ts'
|
||||
import PF, { Grid } from 'pathfinding'
|
||||
import { chunks } from '~/helpers';
|
||||
|
||||
interface SvgContext {
|
||||
array: number[][],
|
||||
paths: string[],
|
||||
width: number,
|
||||
height: number
|
||||
}
|
||||
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 canvasElement: Ref<HTMLCanvasElement | undefined> = ref();
|
||||
|
@ -21,7 +16,14 @@ const startPoint = ref<number[]>()
|
|||
const endPoint = ref<number[]>()
|
||||
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 = () => {
|
||||
loading.value = true
|
||||
|
@ -30,91 +32,182 @@ const beforeUpload = () => {
|
|||
const onUpload = (event: FileUploadUploadEvent) => {
|
||||
try {
|
||||
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()
|
||||
loading.value = false
|
||||
} catch (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)
|
||||
|
||||
newDraw()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
loadingFile.value = false
|
||||
}
|
||||
|
||||
const newDraw = () => {
|
||||
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
|
||||
endPoint.value = undefined
|
||||
startToEndPath.value = undefined
|
||||
|
||||
context.value = canvasElement.value?.getContext('2d') || undefined;
|
||||
const lines = (plan.value as SvgContext).array
|
||||
lines.forEach((line, indexY) => {
|
||||
const lines = point_array.value
|
||||
if (!lines) return;
|
||||
|
||||
context.value?.clearRect(0, 0, cw, ch)
|
||||
await nextFrame()
|
||||
|
||||
for (let indexY = 0; indexY < lines.length; indexY++) {
|
||||
const line = lines[indexY];
|
||||
|
||||
const drawLine = () => {
|
||||
line.forEach((point, indexX) => {
|
||||
if (canvasElement.value && context.value) {
|
||||
context.value.fillStyle = point > 0 ? 'red' : 'WHITE'
|
||||
if (canvasElement.value && context.value && point > 0) {
|
||||
context.value.fillStyle = 'crimson'
|
||||
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))
|
||||
// console.log(t)
|
||||
|
||||
grid.value = new PF.Grid((plan.value as SvgContext).array.map(y => y.map(x => x > 0 ? 1 : 0)))
|
||||
}
|
||||
drawLine()
|
||||
await nextFrame()
|
||||
}
|
||||
grid.value = new PF.Grid(lines.map(y => y.map(x => x > 0 ? 1 : 0)))
|
||||
}
|
||||
|
||||
const setPoint = (event: MouseEvent) => {
|
||||
try {
|
||||
if (!event.currentTarget) return
|
||||
const target = (<HTMLCanvasElement>event.currentTarget)
|
||||
const bound = target.getBoundingClientRect()
|
||||
|
||||
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)
|
||||
});
|
||||
const toggleBlock = (name: string) => {
|
||||
if (openBlocks.value.includes(name)) {
|
||||
openBlocks.value.splice(openBlocks.value.indexOf(name), 1)
|
||||
} else {
|
||||
newDraw()
|
||||
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 {
|
||||
loadingFile.value = true
|
||||
const res = await fetch(`${config.public.apiBase}/api/floorplan/`)
|
||||
const data = await res.json()
|
||||
files.value = data
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
loadingFile.value = false
|
||||
}
|
||||
onMounted(async () => {
|
||||
await loadFiles()
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<div class="flex flex-col gap-4">
|
||||
<Panel header="Загрузка файла">
|
||||
<FileUpload mode="basic" name="demo" :url="`${config.public.apiBase}/api/floorplan`" accept="image/*"
|
||||
<Panel header="Выбор пресета">
|
||||
<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"
|
||||
chooseLabel="Выберите файл" :disabled="loading" />
|
||||
</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>
|
||||
</div>
|
||||
</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>
|
|
@ -1,22 +1,15 @@
|
|||
from django.db import models
|
||||
import json
|
||||
|
||||
|
||||
# Create your models here.
|
||||
class Product(models.Model):
|
||||
title = models.CharField(max_length=100)
|
||||
description = models.TextField(default=None, null=True)
|
||||
model3d = models.FileField(
|
||||
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"
|
||||
)
|
||||
image3 = models.ImageField(
|
||||
default=None, blank=True, null=True, upload_to="files"
|
||||
)
|
||||
model3d = models.FileField(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")
|
||||
image3 = models.ImageField(default=None, blank=True, null=True, upload_to="files")
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
@ -25,3 +18,6 @@ class Product(models.Model):
|
|||
class Floorplan(models.Model):
|
||||
title = models.CharField(max_length=200)
|
||||
np_field = models.TextField()
|
||||
d_size = models.IntegerField(null=True, blank=True)
|
||||
d_border = models.IntegerField(null=True, blank=True)
|
||||
paths = models.TextField()
|
|
@ -1,6 +1,8 @@
|
|||
from rest_framework import routers, serializers, viewsets
|
||||
from .models import Product, Floorplan
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger("root")
|
||||
|
||||
class ProductSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
|
@ -16,9 +18,22 @@ class ProductSerializer(serializers.HyperlinkedModelSerializer):
|
|||
]
|
||||
|
||||
|
||||
class FloorplanSerializer(serializers.Serializer):
|
||||
title = serializers.CharField(max_length=200)
|
||||
np_field = serializers.CharField()
|
||||
class FloorplanSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Floorplan
|
||||
fields = [
|
||||
"id",
|
||||
"title",
|
||||
"np_field",
|
||||
"d_border",
|
||||
"d_size",
|
||||
"paths"
|
||||
]
|
||||
|
||||
def create(self,validated_data):
|
||||
return Floorplan.objects.create(**validated_data)
|
||||
class FloorplanListSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Floorplan
|
||||
fields = [
|
||||
"id",
|
||||
"title",
|
||||
]
|
|
@ -31,7 +31,7 @@ def read_image(content: bytes) -> np.ndarray:
|
|||
|
||||
def parse_image(img):
|
||||
(img_h, img_w) = img.shape[:2]
|
||||
t = 1200
|
||||
t = 1920
|
||||
w = t
|
||||
h = int((img_h / img_w) * t)
|
||||
img = cv2.resize(img, (w, h))
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
|
||||
import json
|
||||
from rest_framework.parsers import JSONParser, MultiPartParser
|
||||
from rest_framework.views import APIView
|
||||
from django.http import JsonResponse
|
||||
|
||||
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
|
||||
|
||||
import logging
|
||||
|
@ -38,26 +38,43 @@ class FloorplanView(APIView):
|
|||
logger.info(file.__dict__)
|
||||
res = parse_image(read_image(file.read()))
|
||||
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():
|
||||
serializer.save()
|
||||
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)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
raise e
|
||||
|
||||
def get(self, request):
|
||||
def get(self, request, id=None):
|
||||
try:
|
||||
item = Floorplan.objects.last()
|
||||
if id is not None:
|
||||
item = Floorplan.objects.get(id=id)
|
||||
serializer = FloorplanSerializer(item, many=False)
|
||||
data = serializer.data
|
||||
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:
|
||||
logger.error(e)
|
||||
raise e
|
||||
|
|
|
@ -23,5 +23,6 @@ from django.views.decorators.csrf import csrf_exempt
|
|||
urlpatterns = [
|
||||
path("admin/", admin.site.urls),
|
||||
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')
|
||||
|
|
|
@ -12,7 +12,7 @@ const canvasElement = ref();
|
|||
const context = ref();
|
||||
|
||||
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 startToEndPath = ref()
|
||||
|
||||
|
@ -30,12 +30,26 @@ const newDraw = () => {
|
|||
lines.forEach((line, indexY) => {
|
||||
line.forEach((point, indexX) => {
|
||||
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)
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// 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
|
||||
quantum_lines.forEach((line, indexY) => {
|
||||
line.forEach((point, indexX) => {
|
||||
|
@ -75,11 +89,13 @@ onMounted(async () => {
|
|||
await floorplan.getData()
|
||||
newDraw()
|
||||
})
|
||||
const cw = 1920
|
||||
const ch = 800
|
||||
</script>
|
||||
<template>
|
||||
<div class="container" style="display: flex; justify-content: center; align-items: center; flex-direction: column;">
|
||||
<canvas ref="canvasElement" width="1200" height="600"></canvas>
|
||||
<svg ref="svgElement" width="1200" height="600" style="position: absolute;">
|
||||
<canvas ref="canvasElement" :width="cw" :height="ch"></canvas>
|
||||
<svg ref="svgElement" :width="cw" :height="ch" style="position: absolute;">
|
||||
<path v-for="item in paths" :d="item.path" @click="setPointSvg(item)" :class="[
|
||||
{ 'unwalkable': item.unwalkable },
|
||||
{ 'endPoint': (endPoint && item.x == endPoint.x && item.y == endPoint.y) },
|
||||
|
@ -100,7 +116,7 @@ svg path:hover {
|
|||
}
|
||||
|
||||
svg path.unwalkable {
|
||||
fill: rgba(0, 0, 0, 0.5);
|
||||
/* fill: rgba(0, 0, 0, 0.5); */
|
||||
}
|
||||
|
||||
svg path.endPoint {
|
||||
|
|
|
@ -6,7 +6,7 @@ export const useFloorplanStore = defineStore('floorplan', {
|
|||
state: () => {
|
||||
return {
|
||||
title: undefined,
|
||||
chunkSize: 5,
|
||||
chunkSize: 7,
|
||||
np_array: [] as number[][],
|
||||
prepared_array: [] as number[][]
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ export const useFloorplanStore = defineStore('floorplan', {
|
|||
})
|
||||
})
|
||||
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) {
|
||||
|
|
Loading…
Reference in New Issue