diff --git a/CHANGELOG.md b/CHANGELOG.md index fcd619d0..f67a8b0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Nanoleaf: Wizard to generate user authorization token allowing users to configure the device via a single window -- Nanoleaf: Generation of a default layout per device's configuration +- Nanoleaf: Generation of a default layout per device's configuration, including oriantation ### Changed @@ -21,7 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Nanoleaf: "Panel numbering sequence" was not configurable any longer - Nanoleaf: Number of panels increased during retries (#1643) -## Removed +### Removed - Nanoleaf: Removed "Start Position" in favour of the general Blacklist feature provided ## [2.0.15](https://github.com/hyperion-project/hyperion.ng/releases/tag/2.0.15) - 2023-02 diff --git a/assets/webconfig/js/content_leds.js b/assets/webconfig/js/content_leds.js index 8a22f98d..34716f1f 100755 --- a/assets/webconfig/js/content_leds.js +++ b/assets/webconfig/js/content_leds.js @@ -1697,7 +1697,7 @@ $(document).ready(function () { if (ledDeviceProperties) { var panelOrderTopDown = conf_editor.getEditor("root.specificOptions.panelOrderTopDown").getValue() === "top2down"; var panelOrderLeftRight = conf_editor.getEditor("root.specificOptions.panelOrderLeftRight").getValue() === "left2right"; - var ledArray = nanoleafGeneratelayout(ledDeviceProperties.panelLayout.layout, panelOrderTopDown, panelOrderLeftRight); + var ledArray = nanoleafGeneratelayout(ledDeviceProperties.panelLayout, panelOrderTopDown, panelOrderLeftRight); aceEdt.set(ledArray); isGenerated = true; } @@ -2480,8 +2480,14 @@ function sortByPanelCoordinates(arr, topToBottom, leftToRight) { } }); } +function rotateCoordinates(x, y, radians) { + var rotatedX = x * Math.cos(radians) - y * Math.sin(radians); + var rotatedY = x * Math.sin(radians) + y * Math.cos(radians); -function nanoleafGeneratelayout(layout, panelOrderTopDown, panelOrderLeftRight) { + return { x: rotatedX, y: rotatedY }; +} + +function nanoleafGeneratelayout(panelLayout, panelOrderTopDown, panelOrderLeftRight) { // Dictionary for Nanoleaf shape types let shapeTypes = { @@ -2496,7 +2502,7 @@ function nanoleafGeneratelayout(layout, panelOrderTopDown, panelOrderLeftRight) 9: { name: "ShapesMiniTriangle", sideLengthX: 67, sideLengthY: 67 }, 12: { name: "ShapesController", sideLengthX: 0, sideLengthY: 0 }, 14: { name: "ElementsHexagon", sideLengthX: 134, sideLengthY: 134 }, - 15: { name: "ElementsHexagonCorner", sideLengthX: 33.5, sideLengthX: 58 }, + 15: { name: "ElementsHexagonCorner", sideLengthX: 33.5, sideLengthY: 58 }, 16: { name: "LinesConnector", sideLengthX: 11, sideLengthY: 11 }, 17: { name: "LightLines", sideLengthX: 154, sideLengthY: 154 }, 18: { name: "LightLinesSingleZone", sideLengthX: 77, sideLengthY: 77 }, @@ -2505,20 +2511,36 @@ function nanoleafGeneratelayout(layout, panelOrderTopDown, panelOrderLeftRight) 999: { name: "Unknown", sideLengthX: 100, sideLengthY: 100 } }; - let { positionData, numPanels, sideLength } = layout; - var minX = positionData[0].x; - var maxX = positionData[0].x; - var minY = positionData[0].y; - var maxY = positionData[0].y; + let { globalOrientation, layout } = panelLayout; + var positionData = layout.positionData; + var degreesToRotate = 0; + if (globalOrientation) { + degreesToRotate = globalOrientation.value; + } + // Convert degrees to radians + var radians = (degreesToRotate * Math.PI) / 180; + + var rotatedCoordinates = rotateCoordinates(positionData[0].x, positionData[0].y, radians); + var minX = rotatedCoordinates.x; + var maxX = rotatedCoordinates.x; + var minY = rotatedCoordinates.y; + var maxY = rotatedCoordinates.y; //Define capture rectangle per panel var factorPartial = 0.25; + positionData.forEach(panel => { if (shapeTypes[panel.shapeType] == undefined) { panel.shapeType = 999; } + if (radians !== 0) { + rotatedCoordinates = rotateCoordinates(panel.x, panel.y, radians); + panel.x = rotatedCoordinates.x; + panel.y = rotatedCoordinates.y; + } + panel.maxX = panel.x + shapeTypes[panel.shapeType].sideLengthX * factorPartial; panel.maxY = panel.y + shapeTypes[panel.shapeType].sideLengthY * factorPartial; panel.shapeName = shapeTypes[panel.shapeType].name; @@ -2548,17 +2570,19 @@ function nanoleafGeneratelayout(layout, panelOrderTopDown, panelOrderLeftRight) sortByPanelCoordinates(positionData, panelOrderTopDown, panelOrderLeftRight); positionData.forEach(panel => { - let layoutObject = { - name: i + "-" + panel.panelId, - hmin: (panel.x - minX) * scaleX, - hmax: (panel.maxX - minX) * scaleX, - //Nanoleaf corodinates start at bottom left, therefore reverse vertical positioning - vmin: 1 - ((panel.maxY - minY) * scaleY), - vmax: 1 - ((panel.y - minY) * scaleY) - }; - ++i; - - layoutObjects.push(JSON.parse(JSON.stringify(layoutObject))); + // Skip non-LED elements + if (panel.sideLengthX !== 0) { + let layoutObject = { + name: i + "-" + panel.panelId, + hmin: (panel.x - minX) * scaleX, + hmax: (panel.maxX - minX) * scaleX, + //Nanoleaf corodinates start at bottom left, therefore reverse vertical positioning + vmin: 1 - ((panel.maxY - minY) * scaleY), + vmax: 1 - ((panel.y - minY) * scaleY) + }; + layoutObjects.push(JSON.parse(JSON.stringify(layoutObject))); + ++i; + } }); return layoutObjects; } diff --git a/libsrc/leddevice/dev_net/LedDeviceNanoleaf.cpp b/libsrc/leddevice/dev_net/LedDeviceNanoleaf.cpp index c3272cfe..f7db661d 100644 --- a/libsrc/leddevice/dev_net/LedDeviceNanoleaf.cpp +++ b/libsrc/leddevice/dev_net/LedDeviceNanoleaf.cpp @@ -4,6 +4,7 @@ //std includes #include #include +#include // Qt includes #include @@ -39,6 +40,8 @@ namespace { const int BRI_MAX = 100; // Panel configuration settings + const char PANEL_GLOBALORIENTATION[] = "globalOrientation"; + const char PANEL_GLOBALORIENTATION_VALUE[] = "value"; const char PANEL_LAYOUT[] = "layout"; const char PANEL_NUM[] = "numPanels"; const char PANEL_ID[] = "panelId"; @@ -240,6 +243,10 @@ bool LedDeviceNanoleaf::initLedsConfiguration() // Get panel details from /panelLayout/layout QJsonObject jsonPanelLayout = jsonAllPanelInfo[API_PANELLAYOUT].toObject(); + + const QJsonObject globalOrientation = jsonPanelLayout[PANEL_GLOBALORIENTATION].toObject(); + double radians = (globalOrientation[PANEL_GLOBALORIENTATION_VALUE].toInt() * std::acos(-1)) / 180; + QJsonObject jsonLayout = jsonPanelLayout[PANEL_LAYOUT].toObject(); _panelLedCount = getHwLedCount(jsonLayout); @@ -256,9 +263,22 @@ bool LedDeviceNanoleaf::initLedsConfiguration() QJsonObject panelObj = value.toObject(); int panelId = panelObj[PANEL_ID].toInt(); - int panelX = panelObj[PANEL_POS_X].toInt(); - int panelY = panelObj[PANEL_POS_Y].toInt(); int panelshapeType = panelObj[PANEL_SHAPE_TYPE].toInt(); + int posX = panelObj[PANEL_POS_X].toInt(); + int posY = panelObj[PANEL_POS_Y].toInt(); + + int panelX; + int panelY; + if (radians != 0) + { + panelX = static_cast(posX * cos(radians) - posY * sin(radians)); + panelY = static_cast(posX * sin(radians) + posY * cos(radians)); + } + else + { + panelX = posX; + panelY = posY; + } DebugIf(verbose, _log, "Panel [%d] (%d,%d) - Type: [%d]", panelId, panelX, panelY, panelshapeType);