From 2a67cd93da06e1eb4a99dcf839b8c9d0794dc043 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Mon, 15 Apr 2024 20:51:15 +0200 Subject: [PATCH 1/3] ADD outlinePolyline --- ...dinates.js => forceIntegerCoordinates.mjs} | 14 +- support/editor/extensions/newPolygon.mjs | 9 ++ support/editor/extensions/outlinePolyline.mjs | 138 ++++++++++++++++++ 3 files changed, 160 insertions(+), 1 deletion(-) rename support/editor/extensions/{forceIntegerCoordinates.js => forceIntegerCoordinates.mjs} (77%) create mode 100644 support/editor/extensions/newPolygon.mjs create mode 100644 support/editor/extensions/outlinePolyline.mjs diff --git a/support/editor/extensions/forceIntegerCoordinates.js b/support/editor/extensions/forceIntegerCoordinates.mjs similarity index 77% rename from support/editor/extensions/forceIntegerCoordinates.js rename to support/editor/extensions/forceIntegerCoordinates.mjs index 611c7232..6d39adac 100644 --- a/support/editor/extensions/forceIntegerCoordinates.js +++ b/support/editor/extensions/forceIntegerCoordinates.mjs @@ -1,3 +1,6 @@ +import { newPolygon } from "./newPolygon.mjs"; +import { polylineToPolygon } from "./outlinePolyline.mjs"; + function forceIntegerCoordinates(mapOrLayer) { tiled.log("Running forceIntegerCoordinates:" + mapOrLayer); if(!mapOrLayer){ @@ -5,7 +8,16 @@ function forceIntegerCoordinates(mapOrLayer) { }; if(mapOrLayer.isObjectLayer) { let objects = mapOrLayer.objects; + var object; for(object of objects) { + if (object.shape == MapObject.Polyline) { + var polygon = polylineToPolygon(object.polygon, 4.0); + var newObject = newPolygon(object); + tiled.log("New object:" + newObject); + newObject.polygon = polygon; + mapOrLayer.addObject(newObject); + }; + object.x = Math.round(object.x); object.y = Math.round(object.y); object.width = Math.round(object.width); @@ -39,4 +51,4 @@ forceIntegerCoordinatesAction.text = "Force Integer Coordinates"; //add this action to the Edit menu: tiled.extendMenu("Edit", [ { action: "ForceIntegerCoordinates", before: "Preferences" } -]); \ No newline at end of file +]); diff --git a/support/editor/extensions/newPolygon.mjs b/support/editor/extensions/newPolygon.mjs new file mode 100644 index 00000000..f0b496f6 --- /dev/null +++ b/support/editor/extensions/newPolygon.mjs @@ -0,0 +1,9 @@ +export function newPolygon(oldObj) { + var object = new MapObject(); + object.x = oldObj.x; + object.y = oldObj.y; + object.width = oldObj.width; + object.height = oldObj.height; + object.shape = MapObject.Polygon; + return object; +} diff --git a/support/editor/extensions/outlinePolyline.mjs b/support/editor/extensions/outlinePolyline.mjs new file mode 100644 index 00000000..8acc47e1 --- /dev/null +++ b/support/editor/extensions/outlinePolyline.mjs @@ -0,0 +1,138 @@ +function getOffsets(a, b, thickness) { + var + dx = b.x - a.x, + dy = b.y - a.y, + len = Math.sqrt(dx * dx + dy * dy), + scale = thickness / (2 * len) + ; + return { + x: -scale * dy, + y: scale * dx + }; +} + +function getIntersection(a1, b1, a2, b2) { + + // directional constants + var + k1 = (b1.y - a1.y) / (b1.x - a1.x), + k2 = (b2.y - a2.y) / (b2.x - a2.x); + + + + // if the directional constants are equal, the lines are parallel + if (Math.abs(k1 - k2)<0.00001) { + return; + } + + // y offset constants for both lines + var m1 = a1.y - k1 * a1.x; + var m2 = a2.y - k2 * a2.x; + + // compute x + var x = (m1 - m2) / (k2 - k1); + + // use y = k * x + m to get y coordinate + var y = k1 * x + m1; + + return { x:x, y:y }; +} + +function isArray(obj){ + return (Object.prototype.toString.call(obj)==='[object Array]'); +} + +function me(points, thickness) { + + + //Convert points into json notation + var arr = []; + for (var i=0; i [pt.x, pt.y]); + tiled.log("Running me:" + points); + var vertices = me(points, thickness); + return vertices.map((pt) => Qt.point(pt[0], pt[1])); +} \ No newline at end of file From 92ed54687b53c1363135eaa82c90f8ae021c679e Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Sun, 19 Jan 2025 17:23:47 +0100 Subject: [PATCH 2/3] UPDATE rollercoaster hash --- src/level_meta/level_data.nim | 6 +++--- support/levels | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/level_meta/level_data.nim b/src/level_meta/level_data.nim index a3f38786..fec219f3 100644 --- a/src/level_meta/level_data.nim +++ b/src/level_meta/level_data.nim @@ -48,7 +48,7 @@ let officialLevels*: OrderedTable[Path, LevelMeta] = @[ newLevelMeta(name= "Novel Navigations", path="levels/novel_navigations.flatty", theme= Bookshelf, hash="83D025E12A1140BC3B86831F20FF4622"), newLevelMeta(name= "Shelf Swinger", path="levels/shelf_swinger.flatty", theme= Bookshelf, hash="E91EE82424E715F5C6F9A439F1096F1B"), newLevelMeta(name= "Under Covers", path="levels/under_covers.flatty", theme= Bookshelf, hash="07C4F9B28FA27A1EDB706A9432544979"), - newLevelMeta(name= "Rollercoaster", path="levels/rollercoaster.flatty", theme= Bookshelf, hash="92330B17118385D29D0549DB1A823312"), + newLevelMeta(name= "Rollercoaster", path="levels/rollercoaster.flatty", theme= Bookshelf, hash="EB073CA2B150DF7EF20C31E8ECB01F86"), newLevelMeta(name= "Hooked", path="levels/hooked.flatty", theme= Bookshelf, hash="C83A58916A6F97F1AA0A2952E12BFABA"), newLevelMeta(name= "Dominoes", path="levels/dominoes.flatty", theme= Bookshelf, hash="19A67112C03DA92C9D51FB268956F93C"), newLevelMeta(name= "Backflip", path="levels/backflip.flatty", theme= Bookshelf, hash="513A5202C29C322690EE9B33068D6789"), @@ -64,11 +64,11 @@ let officialLevels*: OrderedTable[Path, LevelMeta] = @[ newLevelMeta(name= "Treasure Tunnel", path="levels/treasure_tunnel.flatty", theme= Plants, hash="6E5F2C44C7ED48F25ED86E834C68149B"), newLevelMeta(name= "Half-Pipe Jungle", path="levels/halfpipe.flatty", theme= Plants, hash="31609EFBA4AB9DEFD10A4BF90CB5300D"), newLevelMeta(name= "Rickety Bridge", path="levels/rickety_bridge.flatty", theme= Plants, hash="0CF980DB09C2EE873C16836319B51CBD"), - newLevelMeta(name = "Rolling Raiders", path="levels/boulder.flatty", theme= Plants, hash="0541EF41C104AE11FFCE43B3B3077A85"), + newLevelMeta(name = "Rolling Raiders", path="levels/boulder.flatty", theme= Plants, hash="7A93A4DD90103EF4363EB503BFAF0642"), newLevelMeta(name= "Zig Zag Down", path="levels/zig_zag_down.flatty", theme= Desk, hash="633154C6A64C4C0EB4FCC1FE1F0490B0"), newLevelMeta(name = "Time Traveler", path="levels/time_traveler.flatty", theme= Desk, hash="18193FB4744661DA83906690CE211469"), - newLevelMeta(name = "Tight Squeeze", path="levels/tight_squeeze.flatty", theme= Desk, hash="0541EF41C104AE11FFCE43B3B3077A85"), + newLevelMeta(name = "Tight Squeeze", path="levels/tight_squeeze.flatty", theme= Desk, hash="7A93A4DD90103EF4363EB503BFAF0642"), newLevelMeta(name= "Ballistic Bowler", path="levels/ballistic_bowler.flatty", theme= Desk, hash="E7ED841B154ADD2B5694AD6613CCE5D1"), newLevelMeta(name= "Ramp of Pages", path="levels/leg_up.flatty", theme= Desk, hash="6F48907EB90D6985CB66486C4A11FFEC"), newLevelMeta(name= "Ballancing Act", path="levels/ballancing_act.flatty", theme= Desk, hash="15B0EC58F7BB8A9912DB470DE0CCA81F"), diff --git a/support/levels b/support/levels index 79b320f2..2d0238a4 160000 --- a/support/levels +++ b/support/levels @@ -1 +1 @@ -Subproject commit 79b320f2083502ea35b8e91d0ce0cf915f6648d2 +Subproject commit 2d0238a400060d3994de3daa9cca7dfd0aecac62 From d9408e96f0a8968ff4ff4bdb3e85e40faedd04d0 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Mon, 20 Jan 2025 20:52:21 +0100 Subject: [PATCH 3/3] CHANGE outline polygon to run on selected object --- .../extensions/src/apply-wheelsprung-fixes.ts | 13 +++ .../src/{newPolygon.ts => new-polygon.ts} | 0 editor/extensions/wheelsprung/index.js | 106 ++++++++++++++++++ 3 files changed, 119 insertions(+) rename editor/extensions/src/{newPolygon.ts => new-polygon.ts} (100%) diff --git a/editor/extensions/src/apply-wheelsprung-fixes.ts b/editor/extensions/src/apply-wheelsprung-fixes.ts index 8e9c6c7c..4706c432 100644 --- a/editor/extensions/src/apply-wheelsprung-fixes.ts +++ b/editor/extensions/src/apply-wheelsprung-fixes.ts @@ -1,6 +1,9 @@ /// import { ensureWindingOrder } from "./ensure-winding-order"; +import { polylineToPolygon } from "./outline-polyline"; +import { newPolygon } from "./new-polygon"; + export function applyWheelsprungFixes(mapOrLayer) { tiled.log("Running applyWheelsprungFixes:" + mapOrLayer); @@ -23,6 +26,16 @@ export function applyWheelsprungFixes(mapOrLayer) { ); object.polygon = ensureWindingOrder(object.polygon); } + + if (object.shape == MapObject.Polyline && object.selected) { + var polygon = polylineToPolygon(object.polygon, 4.0); + var newObject = newPolygon(object); + tiled.log("New object:" + newObject); + tiled.log("new polygon:" + polygon); + newObject.polygon = polygon; + mapOrLayer.addObject(newObject); + }; + if(object.shape == MapObject.Ellipse && object.className == "DynamicObject") { if(object.width != object.height) { tiled.log("Ellipses not supported for Dynamic Objects. Making circular:" + object); diff --git a/editor/extensions/src/newPolygon.ts b/editor/extensions/src/new-polygon.ts similarity index 100% rename from editor/extensions/src/newPolygon.ts rename to editor/extensions/src/new-polygon.ts diff --git a/editor/extensions/wheelsprung/index.js b/editor/extensions/wheelsprung/index.js index 429e740d..74bdc1cf 100644 --- a/editor/extensions/wheelsprung/index.js +++ b/editor/extensions/wheelsprung/index.js @@ -19,6 +19,103 @@ return vertices; } + // src/outline-polyline.ts + function getOffsets(a, b, thickness) { + var dx = b.x - a.x, dy = b.y - a.y, len = Math.sqrt(dx * dx + dy * dy), scale = thickness / (2 * len); + return { + x: -scale * dy, + y: scale * dx + }; + } + function getIntersection(a1, b1, a2, b2) { + var k1 = (b1.y - a1.y) / (b1.x - a1.x), k2 = (b2.y - a2.y) / (b2.x - a2.x); + if (Math.abs(k1 - k2) < 1e-5) { + return; + } + var m1 = a1.y - k1 * a1.x; + var m2 = a2.y - k2 * a2.x; + var x = (m1 - m2) / (k2 - k1); + var y = k1 * x + m1; + return { x, y }; + } + function isArray(obj) { + return Object.prototype.toString.call(obj) === "[object Array]"; + } + function me(points, thickness) { + var arr = []; + for (var i2 = 0; i2 < points.length; i2++) { + var pt = points[i2]; + arr.push({ + x: pt[0], + y: pt[1] + }); + } + points = arr; + if (!isArray(thickness)) { + var t2 = thickness; + thickness = []; + for (var i2 = 0; i2 < points.length; i2++) { + thickness.push(t2); + } + } + var off, off2, poly = [], isFirst, isLast, prevA, prevB, interA, interB, p0a, p1a, p0b, p1b; + for (var i2 = 0, il = points.length - 1; i2 < il; i2++) { + isFirst = !i2; + isLast = i2 === points.length - 2; + off = getOffsets(points[i2], points[i2 + 1], thickness[i2]); + off2 = getOffsets(points[i2], points[i2 + 1], thickness[i2 + 1]); + p0a = { x: points[i2].x + off.x, y: points[i2].y + off.y }; + p1a = { x: points[i2 + 1].x + off2.x, y: points[i2 + 1].y + off2.y }; + p0b = { x: points[i2].x - off.x, y: points[i2].y - off.y }; + p1b = { x: points[i2 + 1].x - off2.x, y: points[i2 + 1].y - off2.y }; + if (!isFirst) { + interA = getIntersection(prevA[0], prevA[1], p0a, p1a); + if (interA) { + poly.unshift(interA); + } + interB = getIntersection(prevB[0], prevB[1], p0b, p1b); + if (interB) { + poly.push(interB); + } + } + if (isFirst) { + poly.unshift(p0a); + poly.push(p0b); + } + if (isLast) { + poly.unshift(p1a); + poly.push(p1b); + } + if (!isLast) { + prevA = [p0a, p1a]; + prevB = [p0b, p1b]; + } + } + for (var i2 = 0; i2 < poly.length; i2++) { + var pt = poly[i2]; + poly[i2] = [pt.x, pt.y]; + } + poly.push(poly[0]); + return poly; + } + function polylineToPolygon(polygon, thickness) { + var points = polygon.map((pt) => [pt.x, pt.y]); + tiled.log("Running me:" + points); + var vertices = me(points, thickness); + return vertices.map((pt) => Qt.point(pt[0], pt[1])); + } + + // src/new-polygon.ts + function newPolygon(oldObj) { + var object = new MapObject(); + object.x = oldObj.x; + object.y = oldObj.y; + object.width = oldObj.width; + object.height = oldObj.height; + object.shape = MapObject.Polygon; + return object; + } + // src/apply-wheelsprung-fixes.ts function applyWheelsprungFixes(mapOrLayer) { tiled.log("Running applyWheelsprungFixes:" + mapOrLayer); @@ -42,6 +139,15 @@ ); object.polygon = ensureWindingOrder(object.polygon); } + if (object.shape == MapObject.Polyline && object.selected) { + var polygon = polylineToPolygon(object.polygon, 4); + var newObject = newPolygon(object); + tiled.log("New object:" + newObject); + tiled.log("new polygon:" + polygon); + newObject.polygon = polygon; + mapOrLayer.addObject(newObject); + } + ; if (object.shape == MapObject.Ellipse && object.className == "DynamicObject") { if (object.width != object.height) { tiled.log("Ellipses not supported for Dynamic Objects. Making circular:" + object);