claude sync: 2026-07-02 10:59

This commit is contained in:
marcus.hinz
2026-07-02 10:59:36 +02:00
parent 3bb3beaa65
commit 41e74e9946
28 changed files with 1088943 additions and 83 deletions
+3 -1
View File
@@ -6,12 +6,14 @@
"Edit(~/projects/adesso-cpq/**)",
"Edit(~/projects/geko-infra/**)",
"Edit(~/projects/fire-visual/**)",
"Edit(~/projects/geko-fire/**)",
"Edit(~/claude-projects/robotunits/**)"
],
"additionalDirectories": [
"~/projects/geko-core",
"~/projects/adesso-cpq",
"~/projects/geko-infra"
"~/projects/geko-infra",
"~/projects/geko-fire"
]
},
"hooks": {
+286
View File
@@ -0,0 +1,286 @@
<!--
RSS generated by JIRA (1001.0.0-SNAPSHOT#100292-rev:5fda9e0fdd2f2fe2b6bc3376de24f51bf166a518) at Wed Jul 01 12:29:44 UTC 2026
It is possible to restrict the fields that are returned in this document by specifying the 'field' parameter in your request.
For example, to request only the issue key and summary add field=key&field=summary to the URL of your request.
-->
<rss version="0.92" >
<channel>
<title>Jira adesso Group extern</title>
<link>https://adesso-group-extern.atlassian.net</link>
<description>This file is an XML representation of an issue</description>
<language>en-us</language> <build-info>
<version>1001.0.0-SNAPSHOT</version>
<build-number>100292</build-number>
<build-date>30-06-2026</build-date>
</build-info>
<item>
<title>[GEKO-76] Allround-Schutzzaun: Intelligente Steher-Logik</title>
<link>https://adesso-group-extern.atlassian.net/browse/GEKO-76</link>
<project id="12341" key="GEKO">GEKO</project>
<description>&lt;p&gt;Dieses Ticket implementiert die selbstheilende Logik f&#252;r die Steher (Pfosten) des Allround-Schutzzauns. Ein platziertes Allround-Element wird automatisch in drei funktionsf&#228;hige 3D-Komponenten zerlegt. Die Steher passen ihre Bauform (A&#8211;G) nach dem Platzieren via lokalem Event-Listener dynamisch an belegte PMIs an und steuern ihre H&#246;he synchron zu den angeschlossenen Z&#228;unen. Nutzer k&#246;nnen Bauform und H&#246;he &#252;ber das Detailmen&#252; manuell &#252;berschreiben, wobei das UI die w&#228;hlbaren Bauformen streng auf die laut Matrix g&#252;ltigen Optionen einschr&#228;nkt.&lt;/p&gt;
&lt;h3&gt;&lt;a name=&quot;%F0%9F%9F%A6DefinitionofReady%C2%A0&quot;&gt;&lt;/a&gt;&lt;b&gt; Definition of Ready&lt;/b&gt;&#160;&lt;/h3&gt;
&lt;h4&gt;&lt;a name=&quot;Wer%3F%C2%A0&quot;&gt;&lt;/a&gt;&lt;b&gt;Wer?&lt;/b&gt;&#160;&lt;/h4&gt;
&lt;p&gt;Anwender des 3D-Viewings&lt;/p&gt;
&lt;h4&gt;&lt;a name=&quot;Was%3F%C2%A0&quot;&gt;&lt;/a&gt;&lt;b&gt;Was?&lt;/b&gt;&#160;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Automatische Aufspaltung eines Allround-Schutzzaun-Objekts in separate Steher- und Zaunknoten.&lt;/li&gt;
&lt;li&gt;Dynamischer In-Place-Austausch der Steher-Bauform (A&#8211;G) basierend auf belegten PMI-Winkeln.&lt;/li&gt;
&lt;li&gt;Automatische H&#246;hensteuerung des Stehers basierend auf dem Maximum der angeschlossenen Z&#228;une samt Fu&#223;freiheit.&lt;/li&gt;
&lt;li&gt;Implementierung einer fachlichen Ausnahme f&#252;r die L&#246;sch-Kaskadierung bei Schutzz&#228;unen.&lt;/li&gt;
&lt;li&gt;Manuelle Override-M&#246;glichkeit f&#252;r Bauform (dynamisch eingeschr&#228;nkt) und H&#246;he (nur Vergr&#246;&#223;erung) im Detailmen&#252;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Warum?&lt;/b&gt;&#160;&lt;/p&gt;
&lt;p&gt;Steher m&#252;ssen im 3D-Viewer als eigenst&#228;ndige Komponenten agieren, sich aber topologisch korrekt &quot;selbst heilen&quot; (Ecken/Kreuzungen bilden), um dem Nutzer manuelle Arbeit zu ersparen und fehlerfreie St&#252;cklisten zu garantieren.&lt;/p&gt;
&lt;h4&gt;&lt;a name=&quot;Wozu%3F%C2%A0&quot;&gt;&lt;/a&gt;&lt;b&gt;Wozu?&lt;/b&gt;&#160;&lt;/h4&gt;
&lt;p&gt;Gew&#228;hrleistung einer konsistenten Schutzzaun-Topologie im Szenegraphen.&lt;/p&gt;</description>
<environment></environment>
<key id="139414">GEKO-76</key>
<summary>Allround-Schutzzaun: Intelligente Steher-Logik</summary>
<type id="12871" iconUrl="https://adesso-group-extern.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10318?size=medium">Task</type>
<parent id="119259">GEKO-6</parent>
<priority id="10000" iconUrl="https://adesso-group-extern.atlassian.net/images/icons/priorities/critical.svg">Critical</priority>
<status id="14794" iconUrl="https://adesso-group-extern.atlassian.net/" description="">To Do</status>
<statusCategory id="2" key="new" colorName="blue-gray"/>
<resolution id="-1">Unresolved</resolution>
<assignee accountid="712020:1a31ac71-0e6f-49af-83f9-0d630a810204">Marcus Hinz</assignee>
<reporter accountid="712020:0a2bb4c7-7da6-48f0-8264-d021465e5f0f">Lukas H&#246;rger</reporter>
<labels>
</labels>
<created>Wed, 8 Apr 2026 16:57:23 +0200</created>
<updated>Wed, 1 Jul 2026 14:27:06 +0200</updated>
<due></due>
<votes>0</votes>
<watches>0</watches>
<attachments>
</attachments>
<subtasks>
</subtasks>
<customfields>
<customfield id="customfield_13434" key="com.atlassian.jira.plugin.system.customfieldtypes:textfield">
<customfieldname>Ansprechpartner</customfieldname>
<customfieldvalues>
<customfieldvalue>Lukas</customfieldvalue>
</customfieldvalues>
</customfield>
<customfield id="customfield_10000" key="com.atlassian.jira.plugins.jira-development-integration-plugin:devsummarycf">
<customfieldname>Development</customfieldname>
<customfieldvalues>
</customfieldvalues>
</customfield>
<customfield id="customfield_10019" key="com.pyxis.greenhopper.jira:gh-lexo-rank">
<customfieldname>Rank</customfieldname>
<customfieldvalues>
<customfieldvalue>0|i5ji9e:</customfieldvalue>
</customfieldvalues>
</customfield>
<customfield id="customfield_13432" key="com.atlassian.jira.plugin.system.customfieldtypes:select">
<customfieldname>T-Shirt Size - Storypoint</customfieldname>
<customfieldvalues>
<customfieldvalue key="20364"><![CDATA[M]]></customfieldvalue>
</customfieldvalues>
</customfield>
<customfield id="customfield_13430" key="com.atlassian.jira.plugin.system.customfieldtypes:textarea">
<customfieldname> Definition of Ready - Formale Kriterien</customfieldname>
<customfieldvalues>
<customfieldvalue>&lt;h3&gt;&lt;a name=&quot;%F0%9F%93%98Funktionsbeschreibung%3A&quot;&gt;&lt;/a&gt;&lt;b&gt; Funktionsbeschreibung:&lt;/b&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Input:&lt;/b&gt; Platzierungs-, &#196;nderungs- oder L&#246;sch-Events von Allround-Schutzzaunkomponenten im Viewport, sowie manuelle Eingaben im Detailmen&#252;.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Verhalten / Ablauf:&lt;/b&gt;
&lt;ol&gt;
&lt;li&gt;&lt;b&gt;Aufspaltung bei Erst-Einbau (Typ 1):&lt;/b&gt; Wird ein Allround-Element frei platziert, splittet die Engine dieses in drei 3D-Komponenten: &lt;tt&gt;Vorderer Steher&lt;/tt&gt; -&amp;gt; &lt;tt&gt;Zaunelement&lt;/tt&gt; -&amp;gt; &lt;tt&gt;Hinterer Steher&lt;/tt&gt;. Der vordere Steher ist die Wurzel (Weltkoordinaten/Typ 1). Zaun und hinterer Steher h&#228;ngen kaskadierend via PMI (Typ 2) daran.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Anbau von Folge-Elementen (Typ 2):&lt;/b&gt; Snappt ein neues Element an das Ende eines bestehenden Zauns, wird der hintere Steher des Vorg&#228;ngers zum gemeinsamen &lt;em&gt;Verbindungssteher&lt;/em&gt;. Das neue Zaunelement h&#228;ngt an dessen PMI.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Selbstheilende Bauform-Aktualisierung:&lt;/b&gt; Nach dem Mouse-Up-Event pr&#252;ft ein lokales Callback die belegten PMI-Seiten des Stehers. Anhand einer exakten Matrix &lt;em&gt;(siehe separater Algorithmus-Abschnitt unten)&lt;/em&gt; wird das 3D-Modell in-place gegen die passende Bauform (A-G) ausgetauscht.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;H&#246;hen-Synchronisation &amp;amp; Metadaten:&lt;/b&gt; Die Standardh&#246;he ist 2200 mm. Die Steherh&#246;he folgt automatisch dem Maximum aller verbundenen Z&#228;une: &lt;tt&gt;max(Zaunh&#246;he 1 + Fu&#223;freiheit 1, Zaunh&#246;he 2 + Fu&#223;freiheit 2, ...)&lt;/tt&gt;. Jeder Steher f&#252;hrt pro Zaun den unteren Startpunkt (Fu&#223;freiheit) und das obere Ende als Metadatum mit. Weicht die H&#246;he von 2200 mm ab, generiert GEKO einen &lt;em&gt;Sondersteher&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Manuelles Override (Detailmen&#252;):&lt;/b&gt;
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;H&#246;he:&lt;/em&gt; Der Nutzer kann die H&#246;he manuell vergr&#246;&#223;ern. Ein Verkleinern unter das berechnete Minimum wird blockiert.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Bauform:&lt;/em&gt; Der Nutzer kann die automatisch berechnete Bauform im Detailmen&#252; manuell &#252;berschreiben. &lt;b&gt;Wichtig f&#252;r die UI-Logik:&lt;/b&gt; Das Auswahl-Dropdown darf dem Nutzer dynamisch nur die Bauformen (A-G) anbieten, die f&#252;r die aktuelle &quot;Eigene Anbau-Seite&quot; (STARTPUNKT, L oder R) laut der Ermittlungs-Matrix &#252;berhaupt zul&#228;ssig sind. Ist ein Steher beispielsweise auf Anbau-Seite &lt;tt&gt;L&lt;/tt&gt; eingebaut, m&#252;ssen die Optionen &lt;tt&gt;C&lt;/tt&gt; und &lt;tt&gt;E&lt;/tt&gt; im Men&#252; ausgeblendet oder deaktiviert werden.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Kaskadierendes L&#246;schverhalten (Sonderregel):&lt;/b&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Steher l&#246;schen:&lt;/em&gt; Alle direkt verbundenen Z&#228;une werden mitgel&#246;scht.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Zaun l&#246;schen:&lt;/em&gt; Angrenzende Steher ohne weitere Z&#228;une werden mitgel&#246;scht. Angrenzende Steher mit weiteren Z&#228;unen bleiben stehen und aktualisieren ihre Bauform.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;&lt;a name=&quot;Algorithmus%3ASteherBauformermitteln%28%7B%7Blayouttauschensteher%7D%7D%29&quot;&gt;&lt;/a&gt;Algorithmus: Steher-Bauform ermitteln (&lt;tt&gt;layout_tauschen_steher&lt;/tt&gt;)&lt;/h4&gt;
&lt;p&gt;Die Engine ermittelt f&#252;r jeden Steher die Seite des Ankers (ist er selbst am Startpunkt/Typ 1 Platzierung, an der linken (L) oder rechten (R) Seite eines Elements angebaut?) und liest die Winkel der aktuell an ihm belegten PMIs (0&#176;, 90&#176;, 180&#176;). Daraus ergibt sich folgende Matrix zur Bestimmung der Bauform-Artikelnummer (A-G):&lt;/p&gt;
&lt;div class=&apos;table-wrap&apos;&gt;
&lt;table class=&apos;confluenceTable&apos;&gt;&lt;tbody&gt;
&lt;tr&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;Eigene Anbau-Seite&lt;/b&gt;&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;Belegte PMIs am Steher&lt;/b&gt;&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;Resultierende Bauform&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;STARTPUNKT&lt;/b&gt;&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;tt&gt;0&lt;/tt&gt; und &lt;tt&gt;180&lt;/tt&gt;&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;A&lt;/b&gt; (ana)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;STARTPUNKT&lt;/b&gt;&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;tt&gt;180&lt;/tt&gt;&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;B&lt;/b&gt; (bna)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;STARTPUNKT&lt;/b&gt;&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;tt&gt;0&lt;/tt&gt;&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;C&lt;/b&gt; (cna)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;STARTPUNKT&lt;/b&gt;&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;tt&gt;90&lt;/tt&gt; und &lt;tt&gt;180&lt;/tt&gt;&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;D&lt;/b&gt; (dna)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;STARTPUNKT&lt;/b&gt;&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;tt&gt;0&lt;/tt&gt; und &lt;tt&gt;90&lt;/tt&gt;&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;E&lt;/b&gt; (ena)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;STARTPUNKT&lt;/b&gt;&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;tt&gt;0&lt;/tt&gt;, &lt;tt&gt;90&lt;/tt&gt; und &lt;tt&gt;180&lt;/tt&gt;&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;F&lt;/b&gt; (fna)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;STARTPUNKT&lt;/b&gt;&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;em&gt;Sonstige&lt;/em&gt;&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;G&lt;/b&gt; (gna)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;L&lt;/b&gt; (Links)&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;em&gt;(keine)&lt;/em&gt;&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;B&lt;/b&gt; (bna)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;L&lt;/b&gt; (Links)&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;tt&gt;0&lt;/tt&gt;&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;A&lt;/b&gt; (ana)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;L&lt;/b&gt; (Links)&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;tt&gt;90&lt;/tt&gt;&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;D&lt;/b&gt; (dna)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;L&lt;/b&gt; (Links)&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;tt&gt;0&lt;/tt&gt; und &lt;tt&gt;90&lt;/tt&gt;&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;F&lt;/b&gt; (fna)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;L&lt;/b&gt; (Links)&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;em&gt;Sonstige&lt;/em&gt;&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;G&lt;/b&gt; (gna)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;R&lt;/b&gt; (Rechts)&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;em&gt;(keine)&lt;/em&gt;&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;C&lt;/b&gt; (cna)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;R&lt;/b&gt; (Rechts)&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;tt&gt;180&lt;/tt&gt;&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;A&lt;/b&gt; (ana)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;R&lt;/b&gt; (Rechts)&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;tt&gt;90&lt;/tt&gt; und &lt;tt&gt;180&lt;/tt&gt;&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;F&lt;/b&gt; (fna)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;R&lt;/b&gt; (Rechts)&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;em&gt;Sonstige&lt;/em&gt;&lt;/td&gt;
&lt;td class=&apos;confluenceTd&apos;&gt;&lt;b&gt;G&lt;/b&gt; (gna)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;h4&gt;&lt;a name=&quot;NichtZiele%28OutofScope%29&quot;&gt;&lt;/a&gt;Nicht-Ziele (Out of Scope)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Echtzeit-Austausch w&#228;hrend des Ziehens:&lt;/b&gt; Die Bauform- und H&#246;henberechnung triggert niemals w&#228;hrend der Mausbewegung, sondern exakt nach dem Mouse-Up-Event oder nach Best&#228;tigung im Detailmen&#252;.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3&gt;&lt;a name=&quot;%F0%9F%93%91Akzeptanzkriterien%3A&quot;&gt;&lt;/a&gt;&lt;b&gt; Akzeptanzkriterien:&lt;/b&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Jedes Allround-Zaunelement wird beim Platzieren in separat selektierbare Steher- und Zaunkomponenten aufgeteilt.&lt;/li&gt;
&lt;li&gt;Beim sequentiellen Anbau teilen sich zwei Zaunelemente exakt einen gemeinsamen Verbindungssteher.&lt;/li&gt;
&lt;li&gt;Die Steher-Bauform heilt sich nach dem Mouse-Up gem&#228;&#223; der Matrix (A-G) selbst.&lt;/li&gt;
&lt;li&gt;Im Detailmen&#252; kann der Nutzer die Bauform manuell &#252;berschreiben. &lt;b&gt;Das UI schr&#228;nkt die Auswahlm&#246;glichkeiten hierbei strikt und dynamisch auf die f&#252;r diese Anbau-Seite g&#252;ltigen Zeilen der Matrix ein.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;Die Steherh&#246;he entspricht mindestens dem Maximum aus &lt;tt&gt;Zaunh&#246;he + Fu&#223;freiheit&lt;/tt&gt;.&lt;/li&gt;
&lt;li&gt;Manuelle H&#246;hen-Eingaben unter das Minimum werden im UI blockiert.&lt;/li&gt;
&lt;li&gt;Sonderregel L&#246;schen (Steher): L&#246;schen eines Stehers l&#246;scht angebundene Z&#228;une.&lt;/li&gt;
&lt;li&gt;Sonderregel L&#246;schen (Zaun): L&#246;schen eines Zauns l&#246;scht alleinstehende Steher; verbundene Steher bleiben stehen und passen Bauform an.&lt;/li&gt;
&lt;li&gt;Sonderregel L&#246;schen (Kaskade): L&#246;schen eines Stehers f&#252;hrt zur L&#246;schung der angebundenen Z&#228;une. L&#246;schung eines angebundenen Zauns f&#252;hrt, falls vorhanden, zur L&#246;schung alleinstehender Steher&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3&gt;&lt;a name=&quot;%F0%9F%A7%AATestCases%3A&quot;&gt;&lt;/a&gt;&lt;b&gt; Test Cases:&lt;/b&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;&lt;span class=&quot;error&quot;&gt;&amp;#91;L&#246;sch-Kettenabbruch&amp;#93;&lt;/span&gt;&lt;/b&gt;: Strang &lt;tt&gt;Steher A -&amp;gt; Zaun 1 -&amp;gt; Steher B -&amp;gt; Zaun 2 -&amp;gt; Steher C&lt;/tt&gt; aufbauen -&amp;gt; &lt;tt&gt;Steher A&lt;/tt&gt; l&#246;schen -&amp;gt; &lt;em&gt;Ergebnis:&lt;/em&gt; &lt;tt&gt;Zaun 1&lt;/tt&gt; wird gel&#246;scht. &lt;tt&gt;Steher B&lt;/tt&gt; bleibt stehen (da &lt;tt&gt;Zaun 2&lt;/tt&gt; angebunden) und wechselt Bauform. &lt;tt&gt;Zaun 2&lt;/tt&gt; und &lt;tt&gt;Steher C&lt;/tt&gt; bleiben unber&#252;hrt.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span class=&quot;error&quot;&gt;&amp;#91;Bauform-Selbstheilung bei Eck-Anbau&amp;#93;&lt;/span&gt;&lt;/b&gt;: Geraden Zaun platzieren (Verbindungssteher ist Bauform A) -&amp;gt; Neues Zaunelement im 90&#176;-Winkel anbauen -&amp;gt; &lt;em&gt;Ergebnis:&lt;/em&gt; Nach Mouse-Up wechselt der Verbindungssteher sofort in die passende Eck-Bauform laut Matrix.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span class=&quot;error&quot;&gt;&amp;#91;Manuelle Override-Tests &amp;amp; UI-Restriktion&amp;#93;&lt;/span&gt;&lt;/b&gt;: Folge-Zaunelement anbauen (Verbindungssteher befindet sich auf Anbau-Seite &lt;tt&gt;L&lt;/tt&gt;). Verbindungssteher selektieren und Detailmen&#252; &#246;ffnen -&amp;gt; &lt;em&gt;Ergebnis:&lt;/em&gt; Das Dropdown f&#252;r die Bauform bietet nur A, B, D, F und G an. Die Optionen C und E sind nicht w&#228;hlbar oder ausgeblendet. Der Wechsel auf eine zul&#228;ssige Bauform (z. B. F) aktualisiert das 3D-Modell sofort.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3&gt;&lt;a name=&quot;%E2%9A%A0%EF%B8%8FEdgeCases%3A%C2%A0&quot;&gt;&lt;/a&gt;&lt;b&gt;&#9888;&#65039; Edge Cases:&lt;/b&gt;&#160;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;&lt;span class=&quot;error&quot;&gt;&amp;#91;Misch-H&#246;hen an einem Steher&amp;#93;&lt;/span&gt;&lt;/b&gt;: Z&#228;une mit H&#246;hen 2500 mm und 2200 mm treffen sich -&amp;gt; &lt;em&gt;Verhalten:&lt;/em&gt; Steher &#252;bernimmt die maximale H&#246;he und wird zum Sondersteher.&lt;/li&gt;
&lt;/ul&gt;
</customfieldvalue>
</customfieldvalues>
</customfield>
<customfield id="customfield_13429" key="com.atlassian.jira.plugin.system.customfieldtypes:multicheckboxes">
<customfieldname> DoR - Checkliste</customfieldname>
<customfieldvalues>
<customfieldvalue key="20347"><![CDATA[Ziel eindeutig formuliert (W-Fragen vollständig?)]]></customfieldvalue>
<customfieldvalue key="20348"><![CDATA[Ansprechpartner benannt]]></customfieldvalue>
<customfieldvalue key="20349"><![CDATA[Akzeptanzkriterien definiert]]></customfieldvalue>
<customfieldvalue key="20350"><![CDATA[mind. ein Testfall dokumentiert]]></customfieldvalue>
<customfieldvalue key="20351"><![CDATA[Priorität gesetzt]]></customfieldvalue>
<customfieldvalue key="20352"><![CDATA[Edge Cases beschrieben]]></customfieldvalue>
</customfieldvalues>
</customfield>
</customfields>
</item>
</channel>
</rss>
+1 -79
View File
@@ -1,81 +1,3 @@
# Offene Punkte — bei jedem Start prüfen und abhaken
Reihenfolge: Paul · Marcel (fire-visual / Bundle) · cpq.
---
## Paul
### [ ] Schutzzaun „Element" kaputt
- **Wo:** `adesso-cpq/packages/frontend/src/components/building-blocks/ProductBrowser.vue`, Filterzeile (TODO (Paul)).
- **Stand:** Kataloggruppe `Element` im `schutzzaun_basic` per Filter rausgenommen.
- **Nötig:** Element richtig fixen statt ausfiltern.
---
## Marcel — cpq-Selection
### [ ] Selection-Logik
- **Wo:** `adesso-cpq/packages/frontend/src/components/visual/DefaultCommandProzessor.ts`, Events `selection` / `selection-click` (FIXME (Marcel)).
- **Nötig:** Selection-Logik sauber in den Griff bekommen.
---
## Marcel — Scale
### [ ] Scale-Hack vs. PlacementMode — wie lösen?
- **Hack:** `Fire3D.vue` skaliert per `scaleScene` jedes Root-Handle zur Laufzeit mit `0.002`.
- **Konflikt:** PlacementMode überschreibt die Subject-Matrix mit `Vector3.one` (`subject.matrix = bestMatrix · dragPointTransform⁻¹`). DragPoint-Transform trägt `S`, sein Inverses `1/S`, Subject bekommt `1/S` → Geometrie netto `S·1/S = 1` → ~500×.
- **Folge:** Jeder einheitliche Laufzeit-Scale (Root, Wrapper, „kleine" Selection) überlebt den Snap nicht. Hack und PlacementMode sind auf demselben Subject unvereinbar.
- **Einzige überlebende Lösung:** `S=1`, also reale kleine Koordinaten in den Daten selbst — Geometrie **und** PMIs konsistent, kein Laufzeit-Scale — plus Kamera-Config (`camera-controller` `defaultPosition`/`fixPoint`, Ortho-Frustum auf mm).
- **Offen/ungeprüft:** Ob fire-visual einen vorgesehenen Mechanismus hat (Unit-System `unitConverter`/`environment.units`; FBX `UnitScaleFactor` greift bisher nur beim Import, nicht auf fertige JSON-SceneGraphen).
- **Entscheidung nötig:** Daten in realer Einheit liefern vs. Lib-Eingriff (PlacementMode behält Subject-Scale).
---
## Marcel (Montag) — fire-visual
### [ ] Lib-Bug movementMode — an fire-visual melden
- **Wo:** `fire-visual` `threed/interaction/module/src/interactionMode/movementMode.ts`, `updateArrowHighlight`.
- **Bug:** Z. 295299 greift `(this.interactionHelperHandle.find('.xy-plane') as Handle).renderer…` **ohne** null-Prüfung — die Achsen (Z. 305318) sind dagegen abgesichert (`if (!arrowElement) return; if (arrowHandle?.renderer)`).
- **Trigger:** Plane-Kind fehlt (Gizmo-Helper existiert, Planes weg — z. B. wenn ein voller `setScene` das Gizmo bei aktivem Move abräumt) → `Cannot read properties of null (reading 'renderer')` in **jedem rAF-Frame** → kompletter Freeze.
- **Fix:** Upstream — Z. 295299 konsistent zu Z. 305318 absichern.
- **Stand:** Cpq-seitig vorerst umschifft, Upstream-Fix trotzdem nötig.
### [ ] Funktionierendes Bundle (`@ad/fire` mit Relations-Resolver)
- **Ist:** cpq lädt `@ad/fire@1.0.5` (gebündelt in `packages/runtime/visual` via `tsup`, gelinkt nach `packages/frontend/node_modules/@ad-cpq/visual-runtime`).
- **Lücke:** 1.0.5 hat `RelationsFeature` + `createRelation`, aber **nicht** `resolveRelations` / Command `resolve_relations` (im Bundle 0 Vorkommen) — der Resolver kam in der fire-visual-Quelle (`~/projects/fire-visual`) erst nach 1.0.5 dazu.
- **Folge:** `attachment_relations` (mit `constraint_position`) wird beim Placement zwar geschrieben und die Relation instanziiert, bleibt aber **inert** (kein Resolver, kein Trigger) → verbundene Teile ziehen beim Move nicht mit.
- **Nötig:** `@ad/fire` auf Stand mit Resolver bringen — fire-visual lokal bauen (`build:local`, yarn-workspaces-Monorepo) → neues `@ad/fire`, cpq's `@ad/fire@1.0.5` darauf umbiegen (pnpm-override / `file:`-Link), `packages/runtime/visual` neu bauen. Achtung API-Drift neuere fire-visual vs. cpq/Runtime.
- **Zusätzlich offen, sobald Resolver da:**
1. **Auto-Trigger fehlt auch in der Quelle**`resolveRelations` nur via Command, kein Update-Hook/Transform-Abo; sauber wäre der Trigger im Move-/Placement-Mode der Engine (mit gezogenem Teil gepinnt), sonst muss cpq es von außen treiben.
2. **Persistenz** — aufgelöste Nachbar-Transforms leben in der Engine, nicht im cpq-eventStore → Readback (`get_transformation`) nötig, sonst Rücksprung beim nächsten `setScene`.
### [ ] Sichtbarer Gap beim Verbau-Ziehen
- **Symptom:** Beim Ziehen eines verbundenen Teils hängen die Follower sichtbar hinterher.
- **Ursache:** `resolutionScheduler` löst **deferred** auf — das gegriffene Teil bewegt der Gizmo in der Input/Update-Phase desselben Frames, die Relationen werden nur **markiert** (`_onTransformChange`) und erst in der **Process-Phase** (`_resolveNow`) aufgelöst, also einen Schritt später.
- **Effekt:** Follower trailen konstant um eine Frame-Bewegung (Gap skaliert mit Ziehgeschwindigkeit; bei Stillstand holen sie im nächsten Frame auf → „im Block"). Kein Timer/Throttle, `MAX_ITERATIONS=10`.
- **Erwartung:** fire-visual nimmt den Gap raus (Auflösung synchron zum Move) **oder** animiert das Nachziehen sauber.
- **Stand:** Cpq-seitig nicht lösbar ohne den Resolver gegen die Lib synchron zu treiben.
### [ ] Null-Matrix-Crash beim `setScene`-Teardown (Relationen + Rotation)
- **Symptom:** Nach mehreren Rotationen verbundener Teile (jede über cpq-`setScene` → Rebuild): `Uncaught Error: Matrix4_4(...zeros...) - inverse: can't be calculated` in `VolumeContext.updateWTL``ColliderComponent.syncTransformation``SynchronizeQueue.process` ← rAF, **jeden Frame** → Freeze. Davor flutet der Log mit `FeatureComponent - deregister` (Teardown der alten Szene).
- **Ursache:** Ein Collider synchronisiert während/nach dem `setScene`-Teardown gegen eine bereits abgeräumte/**genullte** Transform → Null-Matrix → Inverse unmöglich.
- **Repro:** Aktive `attachment_relations` (Position+Rotation) + wiederholtes `setScene`; kumulativ (nach einigen Rebuilds, gleiche Transform-Paarung).
- **Ausgeschlossen:** **Nicht** das Quaternion-Format (`values` = `[w,x,y,z]`, verifiziert), **nicht** Resolver/`localA`/`constraint_rotation` (mit vollständigem Constraint-Satz unverändert). Während des Ziehens (Engine-Live-Resolve) alles korrekt — nur der cpq-`setScene`-Rebuild beim Loslassen triggert es.
- **Einordnung:** Gleiche Klasse wie der movementMode-null-renderer-Freeze — Lib räumt beim Rebuild nicht sauber ab bzw. Collider-Sync läuft gegen tote Transform. Upstream-Fix nötig.
- **Stand:** Cpq-seitig umschifft — `handleRotateEnd` macht **kein** `setScene` mehr (Engine hat den Rotations-Endzustand live korrekt; Event wird nur recorded).
- **Offen:** Ein **nachfolgendes** `setScene` (z. B. Placement nach Rotation) replayt die Rotation und könnte denselben Crash auslösen. Eigentlicher Fix: upstream oder **inkrementelles** Transform-Update (`set_transformation`) statt Full-`setScene` für Move/Rotate.
---
## cpq
### [ ] Verbau-Code refactoren (nach den Klärungen)
- **Wo:** `DefaultCommandProzessor` / `SceneReplayProcessor` / `EventStore` / `eventDataUtil`.
- **Gewachsen über die Klärungsrunden (A-Modell):**
- Move-Ende recorded bewegtes Teil + transitive Follower als eine `pushGroup`-Gruppe.
- Placement schreibt EIN gemeinsames `attachment_relations` (wegen Clobber im `relationsProcessor`).
- Position-Korrektur `pos = event.position dragPMI-Offset`.
- Subject-Ausschluss in DropPoints via `:not`.
- **Stand:** Funktioniert (Kette ≥4, Undo/Redo gruppiert), aber aufräumen.
Keine offenen Punkte.
Binary file not shown.
+1
View File
@@ -8,3 +8,4 @@
- [cpq Storybook starten](cpq-storybook-start.md) — pnpm --filter @ad-cpq/common-frontend storybook (Port 6006)
- [Git nur Fast-Forward](feedback-git-nur-fast-forward.md) — kein rebase/merge/force; bei Divergenz melden statt auflösen
- [fire-visual Placement-Mode](fire-visual-placement-mode.md) — snap-to-point: DragPoints/DropPoints, processInput-Algorithmus, start_placement_mode-Command, PMI-DropPoints
- [cpq Verbau 90° am Steher](cpq-verbau-90grad-steher.md) — Engine kann's, cpq-GroupProcessor (translation-only) plättet die Rotation beim Replay; Punktdaten tragen die Orientierung schon
@@ -0,0 +1,28 @@
---
name: cpq-verbau-90grad-steher
description: "Ziel 90°-Anbau am Steher wie jetzt Links/Rechts — Engine kann es, cpq-GroupProcessor (translation-only) ist der Blocker"
metadata:
node_type: memory
type: project
originSessionId: e3d54daa-eb88-474f-9e99-62bfe83821b2
---
Ziel: an den Stehern im 90°-Winkel anbauen können, genau wie der jetzige Links/Rechts-Verbau.
**Wer ist der Blocker: wir (cpq), nicht fire-visual.**
- **fire-visual kann es.** Das Live-Snapping im PlacementMode setzt die Subject-Matrix als `bestMatrix · dragPointTransform⁻¹` — die Rotation des Drag-Punkts ist drin, die Engine richtet also den vollen Frame aus und dreht das Teil beim Snap schon korrekt um 90°. (Vorbehalt: aus der Placement-Matrix-Notiz abgeleitet, nicht aus frischem Quell-Read; bei Bedarf `PlacementMode`-Quelle prüfen, ob DropPoints den Rotations-Frame durchreichen.)
- **cpq verliert es beim Replay.** Nach dem Snap übernehmen wir das Engine-Ergebnis nicht, sondern merken nur „Punkt A trifft Punkt B" (`group-merge` mit zwei PMI-IDs) und rechnen die Anordnung im `GroupProcessor` selbst neu — rein translatorisch. Beim nächsten `setScene` wird die 90°-Drehung auf achsparallel zurückgeplättet.
**Warum schwer — das Dock-Modell ist translation-only, einachsig, gemeinsame Orientierung. Links/Rechts geht nur, weil nie rotiert wird.** Zu ändernde Schichten:
1. `Edge` = `{from,to,fromPmi,toPmi}` kennt keine Rotation → relative Rotation pro Kante nötig.
2. `computePositions` dockt mit `pos(to)=pos(from)+pmi(from)pmi(to)` (nur Position) → Rotation entlang der Kanten komponieren.
3. `pmiLocal` liest nur `position.value`. **Die Orientierung steckt schon in den Daten** (`properties.rotation`), wird aber ignoriert — und Format passt nicht: 3 Euler-Grad (z. B. `CS_EIN_90_0_0``[0,-0,180]`), deklariert als „quaternion", während `transformMath` `[w,x,y,z]` erwartet.
4. Placement-Mode hartverdrahtet auf `.name-CS_LINKS``.name-CS_RECHTS`; Steher-Anschlüsse leben in der `CS_EIN_*`-Familie → neue Drag-/Drop-Selektoren + Open-End-Logik (`occupiedPmis`).
5. `buildDetachEvent`/`areConnected` nehmen einen 1-achsigen Lauf an (dominante Achse, Links→Rechts-Leseordnung) → 90°-Anbau macht den Verbau zum 2D-Baum, Annahmen brechen.
**Datenlage:** kein plain `CS_VORNE`/`CS_HINTEN` (0 Teile); `CS_LINKS`/`CS_RECHTS` nur auf 12 Teilen; Vorne/Hinten nur in `CS_EIN_*` (rotationscodiert: `CS_EIN_VORNE`, `CS_EIN_HINTEN`, `CS_EIN_STEHER_VORNE/HINTEN`, `CS_EIN_90_0_0` …).
**Machbar:** Erweiterung unseres Modells (Rotation konsumieren + entlang Kanten propagieren + Format-Fix), keine Nachgenerierung der Teile — die nötige Orientierung liefern die Punktdaten bereits.
Siehe [[cpq-verbau-architektur]], [[fire-visual-placement-mode]].