Skip to content

Commit

Permalink
Added readout that shows rotation angles and scale in the bottom corn…
Browse files Browse the repository at this point in the history
…er. Improved render times by implementing an optimizion in the wall z-plane sorting algorithm. Code cleanup.
  • Loading branch information
knicholson32 committed Oct 21, 2023
1 parent abfd413 commit cb5fa7c
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 37 deletions.
5 changes: 5 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# Isometric Floorplan

[View the tool here](https://knicholson32.github.io/isometric-floorplan/)

## TODO

[ ] Consider using [this library](https://github.com/w8r/GreinerHormann) instead for polygon unions
[ ] Consider using [gpu.js](https://github.com/gpujs/gpu.js/#readme) to increase speed of wall comparisons
24 changes: 22 additions & 2 deletions src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,25 @@
@tailwind components;
@tailwind utilities;

.noselect {
-webkit-touch-callout: none;
/* iOS Safari */
-webkit-user-select: none;
/* Safari */
-khtml-user-select: none;
/* Konqueror HTML */
-moz-user-select: none;
/* Old versions of Firefox */
-ms-user-select: none;
/* Internet Explorer/Edge */
user-select: none;
/* Non-prefixed version, currently supported by Chrome, Edge, Opera and Firefox */
}

.textTest {
fill: white;
}

.surface,
.poly,
.path {
Expand Down Expand Up @@ -37,11 +56,12 @@

.wall.wireframe,
.door.wireframe {
fill: none;
stroke: #333;
fill: none !important;
stroke: #333 !important;
}

.outline {
stroke: #ffffff;
stroke-width: 3px;
outline-style: none;
}
46 changes: 43 additions & 3 deletions src/lib/orbit/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import type { Point } from '$lib/types';
import type { Svg } from '@svgdotjs/svg.js';

type OrbitCallback = (
fastRender: boolean,
rotation: number,
Expand All @@ -20,12 +23,27 @@ export default class Orbit {
orbitCallback: OrbitCallback;

currentAngles: Angles = { rotation: -45, tilt: 45, scale: 0.5 };
lastAngles: Angles = { rotation: -45, tilt: 45, scale: 0.5 };

wheelTimeoutID: ReturnType<typeof setTimeout> | undefined = undefined;

constructor(target: SVGSVGElement, orbitCallback: OrbitCallback) {
svgSize: Point;
svg: Svg;

text;
// logo;

constructor(svg: Svg, orbitCallback: OrbitCallback) {
this.orbitCallback = orbitCallback;

this.svg = svg;
const target = this.svg.node;

this.svgSize = {
x: new Number(svg.width()).valueOf(),
y: new Number(svg.height()).valueOf()
};

// Reading the value, which was store as "theValue"
const orbitDataRaw = localStorage ? localStorage.getItem('orbit') : null;
if (orbitDataRaw !== null) {
Expand All @@ -46,7 +64,7 @@ export default class Orbit {
clearTimeout(this.wheelTimeoutID);
this.wheelTimeoutID = undefined;
}
const delta = Math.sign(event.deltaY);
const delta = event.deltaY / 2;
this.move(0, 0, delta, true);
this.wheelTimeoutID = setTimeout(() => this.move(0, 0, 0, false), 500);
});
Expand All @@ -57,9 +75,28 @@ export default class Orbit {

document.onmouseup = (event: MouseEvent) =>
this.move(event.movementX, event.movementY, 0, false);

this.text = this.svg.plain('');

this.text.addClass('textTest');
this.text.addClass('noselect');
this.text.translate(5, this.svgSize.y - 8);
this.text.font({
family: 'Menlo',
size: 10
});
this.text.opacity(0.3);
this.move(0, 0, 0, false);
}

drawAngles() {
this.text.text(
`${this.currentAngles.rotation.toFixed(1)}° ${this.currentAngles.tilt.toFixed(
1
)} x${this.currentAngles.scale.toFixed(2)}`
);
}

saveOrbitData() {
if (localStorage) {
const orbitData = {
Expand Down Expand Up @@ -92,6 +129,9 @@ export default class Orbit {
heightNormalized,
this.currentAngles.scale
);
if (!fastRender) this.saveOrbitData();
if (!fastRender) {
this.saveOrbitData();
}
this.drawAngles();
}
}
50 changes: 23 additions & 27 deletions src/lib/shapes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,8 @@ export class Surface extends Entity {
eq = (x: number): number => x;
slope = NaN;

lowY = 0;
highY = 0;
updateEq() {
// Protect against an odd slope
if (Math.abs(this.point1.x - this.point2.x) < 0.1) {
Expand All @@ -311,6 +313,8 @@ export class Surface extends Entity {
const b = this.point1.y - m * this.point1.x;

this.eq = (x) => m * x + b;
this.lowY = this.point1.y < this.point2.y ? this.point1.y : this.point2.y;
this.highY = this.point1.y > this.point2.y ? this.point1.y : this.point2.y;
}

reset() {
Expand Down Expand Up @@ -339,17 +343,6 @@ export class Surface extends Entity {
}

draw(fastRender: boolean, heightNormalized: number) {
this.renderOrderCache = {};
for (const s of this.shapes) s.clear();

if (fastRender) {
for (const s of this.shapes) s.addClass('wireframe');
} else {
for (const s of this.shapes) s.removeClass('wireframe');
if (this.shapes.length > 1) this.container.front();
else this.shapes[0].front();
}

const translated1: Types.Point = {
x: this.point1.x + this._runningTranslate.x,
y: this.point1.y + this._runningTranslate.y
Expand Down Expand Up @@ -385,19 +378,24 @@ export class Surface extends Entity {
polygons = this.feature.render(translated1, translated2, heightNormalized);
}

if (fastRender) {
for (const s of this.shapes) s.addClass('wireframe');
} else {
for (const s of this.shapes) s.clear();
for (const s of this.shapes) s.removeClass('wireframe');
if (this.shapes.length > 1) this.container.front();
else this.shapes[0].front();
}

// Draw all the polygons
for (let i = 0; i < this.shapes.length && i < polygons.length; i++)
this.shapes[i].plot(polygons[i]);
}

isRenderedBefore(b: Surface, debug = false): boolean | undefined {
// if (fast) {
// if (this.getLowestPoint() > b.getLowestPoint()) return false;
// return true;
// }

// TODO: There may be a speedup by analyzing the range of y values:
// if all y values are larger on one line, it is above?
isRenderedBefore(b: Surface, _debug = false): boolean | undefined {
// If one segment is entirely above or below the other one, this is easy
if (this.highY < b.lowY) return true;
if (b.highY < this.lowY) return false;

// If either slope is NaN (vertical line) we won't be able to tell which is above the other
if (b.index in this.renderOrderCache) {
Expand All @@ -409,9 +407,6 @@ export class Surface extends Entity {
if (r === undefined) return undefined;
return !r;
}
if (debug) console.log('this', this);
if (debug) console.log('b', b);
if (debug) console.log('slopes', this.slope, b.slope);
if (isNaN(this.slope) || isNaN(b.slope)) {
this.renderOrderCache[b.index] = undefined;
return undefined;
Expand All @@ -421,13 +416,11 @@ export class Surface extends Entity {
[this.point1.x, this.point2.x],
[b.point1.x, b.point2.x]
);
if (debug) console.log('overlap', overlap);

if (overlap) {
// They overlap. It may be a segment, or just one point.
if (Math.abs(overlap[0] - overlap[1]) < 0.001) {
// Single point overlap. We still don't know anything
if (debug) console.log('very small overlap');
this.renderOrderCache[b.index] = undefined;
return undefined;
} else {
Expand All @@ -438,8 +431,6 @@ export class Surface extends Entity {
const thisY = this.eq(midpoint);
const bY = b.eq(midpoint);

if (debug) console.log('y values', thisY, bY);

if (thisY > bY) {
// This object is lower in the scene, and is therefore "above", or rendered after the other object
this.renderOrderCache[b.index] = false;
Expand Down Expand Up @@ -488,9 +479,14 @@ export class Extrusion extends PolyWrapper {
return highestPointIndex;
}

draw(_fastRender: boolean, height: number) {
draw(fastRender: boolean, height: number) {
this.poly.clear();

if (fastRender) {
this.poly.opacity(0);
return;
}

const lowerPoly: Types.Point[] = [];
const upperPoly: Types.Point[] = [];
for (const point of this.points) {
Expand Down
7 changes: 3 additions & 4 deletions src/lib/tools/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ export const transform = (
};

export const sortSurfaces = (surfaces: Surface[], fast = true) => {
const toSort = surfaces.concat([]);
const toDraw = [];
if (fast) {
return surfaces;
} else {
const toSort = surfaces.concat([]);
const toDraw = [];
// We need to loop through each z-slot and find the best shape to go there
// We will describe "best" as no other shapes are below it ~and~ as few undefined orders as possible

Expand Down Expand Up @@ -84,9 +84,8 @@ export const sortSurfaces = (surfaces: Surface[], fast = true) => {
toSort.splice(idx, 1);
}
}
return toDraw;
}

return toDraw;
};

/**
Expand Down
2 changes: 1 addition & 1 deletion src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
}
}
new orbit(svg.node, frame);
new orbit(svg, frame);
});
</script>

Expand Down

0 comments on commit cb5fa7c

Please sign in to comment.