338 lines
21 KiB
XML
338 lines
21 KiB
XML
<!--
|
||
RSS generated by JIRA (1001.0.0-SNAPSHOT#100292-rev:f152b838bb945118c071b297741ecc5e36093b62) at Fri Jul 03 09:13:25 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-16] Schutzzaun im Layout schließen/Schutzzaun zwischen zwei Punkten planen</title>
|
||
<link>https://adesso-group-extern.atlassian.net/browse/GEKO-16</link>
|
||
<project id="12341" key="GEKO">GEKO</project>
|
||
<description><p>Dieses Ticket implementiert die interaktive Planung eines Schutzzauns zwischen zwei Punkten im 3D-Layout. Die Funktion ermöglicht das Ziehen einer Strecke, berechnet die Geometrie und generiert den Zaun als kaskadierende Baugruppe. Neu ist die intelligente Vererbungslogik: Werden PMIs als Start- oder Endpunkt genutzt, erbt der Zaun Typ und Füllung automatisch; andernfalls werden diese über ein modales Overlay abgefragt.</p>
|
||
|
||
<h3><a name="%F0%9F%9F%A6DefinitionofReady%C2%A0"></a><b>�� Definition of Ready</b> </h3>
|
||
|
||
<h4><a name="Wer%3F%C2%A0"></a><b>Wer?</b> </h4>
|
||
|
||
<p>Anwender des Schutzzaun-Konfigurators im 3D-Layout.</p>
|
||
|
||
<h4><a name="Was%3F%C2%A0"></a><b>Was?</b> </h4>
|
||
|
||
<ul>
|
||
<li>Interaktives Setzen von Start- und Endpunkt (frei oder gesnappt an PMIs).</li>
|
||
<li>Dynamische Anzeige von 3 Bemaßungen (Länge, Diagonale, Winkel) während der Mausbewegung.</li>
|
||
<li>Intelligente Eigenschafts-Vererbung (Typ/Füllung) basierend auf Start-/End-PMIs zur Vermeidung unnötiger UI-Abfragen.</li>
|
||
<li>Filterung von PMIs: Inkompatible End-PMIs werden nach der Auswahl des Start-PMIs ignoriert und nicht gehighlighted.</li>
|
||
<li>Mathematische Berechnung von 2D-Länge (XZ-Ebene) und Ausrichtungswinkel.</li>
|
||
<li>Algorithmus-gestützte Aufteilung der Strecke in Standard- und Sonderelemente.</li>
|
||
<li>Generierung des Zauns als kaskadierender Verbund (Typ 2 Einbaubedingungen).</li>
|
||
</ul>
|
||
|
||
|
||
<h4><a name="Warum%3F%C2%A0"></a><b>Warum?</b> </h4>
|
||
|
||
<p>Effiziente Planung von Schutzzäunen über größere Distanzen, ohne dass der Nutzer jedes Element einzeln platzieren muss und unter Vermeidung von fehlerhaften Typen-Mischungen.</p>
|
||
|
||
<h4><a name="Wozu%3F%C2%A0"></a><b>Wozu?</b> </h4>
|
||
|
||
<p>Ein strukturierter, in den Szenegraphen integrierter Schutzzaun-Zug, mit dem offene Züge geschlossen werden können.</p></description>
|
||
<environment></environment>
|
||
<key id="139286">GEKO-16</key>
|
||
<summary>Schutzzaun im Layout schließen/Schutzzaun zwischen zwei Punkten planen</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="10001" iconUrl="https://adesso-group-extern.atlassian.net/images/icons/priorities/major.svg">Major</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örger</reporter>
|
||
<labels>
|
||
</labels>
|
||
<created>Wed, 8 Apr 2026 11:43:54 +0200</created>
|
||
<updated>Thu, 2 Jul 2026 14:28:25 +0200</updated>
|
||
<due></due>
|
||
<votes>0</votes>
|
||
<watches>0</watches>
|
||
<attachments>
|
||
</attachments>
|
||
<subtasks>
|
||
</subtasks>
|
||
<customfields>
|
||
<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|i5ji9k:</customfieldvalue>
|
||
|
||
</customfieldvalues>
|
||
</customfield>
|
||
<customfield id="customfield_13432" key="com.atlassian.jira.plugin.system.customfieldtypes:select">
|
||
<customfieldname>T-Shirt Size - Storypoint</customfieldname>
|
||
<customfieldvalues>
|
||
<customfieldvalue key="20365"><![CDATA[L]]></customfieldvalue>
|
||
|
||
</customfieldvalues>
|
||
</customfield>
|
||
<customfield id="customfield_13430" key="com.atlassian.jira.plugin.system.customfieldtypes:textarea">
|
||
<customfieldname>�� Definition of Ready - Formale Kriterien</customfieldname>
|
||
<customfieldvalues>
|
||
<customfieldvalue><h3><a name="%F0%9F%93%98Funktionsbeschreibung%3A"></a><b>�� Funktionsbeschreibung:</b></h3>
|
||
|
||
<p><b>Input:</b> Klick-Events im 3D-Viewport und ggf. Auswahl-Events im modalen Overlay.</p>
|
||
|
||
<ul>
|
||
<li><b>Verhalten / Ablauf:</b>
|
||
<ol>
|
||
<li><b>Startpunkt (Klick 1):</b> Nutzer setzt den ersten Punkt (Typ 1 Weltkoordinaten oder Typ 2 PMI).</li>
|
||
<li><b>Zeichnen &amp; Filtern:</b> Unmittelbar <b>nach dem 1. Klick</b> (sofern dieser an einem PMI erfolgte) filtert die Engine den Szenegraphen. Anhand des Typs des Start-PMIs (z. B. Basic) werden alle inkompatiblen PMIs (z. B. Allround) für den aktuellen Zeichen-Modus als ungültig markiert. Während der Nutzer nun die Gummiband-Linie zum Endpunkt zieht, werden diese inkompatiblen PMIs konsequent nicht gehighlighted und können nicht angeklickt werden.</li>
|
||
<li><b>Endpunkt (Klick 2):</b> Nutzer setzt den zweiten Punkt.</li>
|
||
<li><b>Vererbungslogik &amp; Konfiguration:</b> Die Engine entscheidet anhand folgender Logik-Matrix, woher die Parameter (Typ/Füllung) stammen:
|
||
<ul>
|
||
<li><b>Start: Frei | Ende: Frei</b> → Keine Vererbung. Das modale Auswahl-Overlay öffnet sich. Standard-Elemente werden nach Bestätigung generiert.</li>
|
||
<li><b>Start: PMI | Ende: Frei</b> → Vererbung der Properties vom Start-PMI. Das Overlay erscheint <b>nicht</b>.</li>
|
||
<li><b>Start: Frei | Ende: PMI</b> → Vererbung der Properties vom End-PMI. Das Overlay erscheint <b>nicht</b>.</li>
|
||
<li><b>Start: PMI | Ende: PMI</b> → Vererbung der Properties vom Start-PMI. (Typengleichheit ist durch das Filtern in Schritt 2 bereits sichergestellt). Das Overlay erscheint <b>nicht</b>.</li>
|
||
</ul>
|
||
</li>
|
||
<li><b>Geometrie-Berechnung:</b> Y-Offset und Rotationen werden ignoriert. Absolute Strecke über Pythagoras ({{L = √(Δx² + Δz²)}}), Winkel über <tt>atan2(Δz, Δx)</tt> (auf XZ-Ebene projiziert).</li>
|
||
<li><b>Element-Aufteilung:</b> Die Logik <tt>berechnung_aufteilung_laenge</tt> ermittelt die Rasterelemente <em>(siehe Algorithmus-Abschnitt unten)</em>.</li>
|
||
<li><b>Generierung:</b> Elemente werden kaskadierend via PMI (Typ 2) eingebaut.</li>
|
||
<li><b>Validierung:</b> Trigger der lokalen Validierungsengine.</li>
|
||
</ol>
|
||
</li>
|
||
</ul>
|
||
|
||
|
||
<h4><a name="Algorithmus%3AElementAufteilung%28%7B%7Bberechnungaufteilunglaenge%7D%7D%29"></a>Algorithmus: Element-Aufteilung (<tt>berechnung_aufteilung_laenge</tt>)</h4>
|
||
|
||
<ul>
|
||
<li><b>1. Grundkonfiguration:</b>
|
||
<ul>
|
||
<li><b>Typ "Basic":</b> Der Elementabstand wird als Parameter übergeben; es gibt keinen Steherzusatz (0 mm).</li>
|
||
<li><b>Typ "Allround":</b> Fester Elementabstand von <b>11 mm</b>, Steherzusatz von <b>51 mm</b> pro Element.</li>
|
||
<li><b>Türen:</b> Ist eine Tür in der Konfiguration enthalten, wird pauschal ein Maß von <b>1124 mm</b> (zzgl. Elementabstand) von der Gesamtbreite abgezogen.</li>
|
||
</ul>
|
||
</li>
|
||
<li><b>2. Standardelemente (Greedy):</b> Der Raum wird systematisch mit den größten passenden Standardelementen gefüllt (Priorität: 1507, 1034, 776, 518 mm).</li>
|
||
<li><b>3. Dead Zone Correction (Todeszone):</b> Bleibt eine kritische Restbreite (zwischen 43 mm und Mindestbreite der Füllung) übrig, wird das kleinste bereits verplante Element downgradet (z. B. 776 mm -&gt; 518 mm) oder gelöscht, um Platz für ein produzierbares Sonderelement zu schaffen.</li>
|
||
<li><b>4. Sonderelement (Rasterung):</b> Aus der Restbreite wird im <b>43-mm-Raster</b> das finale Passstück ermittelt. Restlücken &lt; 43 mm werden als Toleranz ignoriert.</li>
|
||
</ul>
|
||
|
||
|
||
<p><b>Pseudocode der Aufteilungslogik:</b></p>
|
||
|
||
<div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
|
||
<pre>FUNCTION calculate_width_distribution(type, has_door, gap_input, total_width, filling_type)
|
||
INITIALIZE results AS dictionary
|
||
|
||
// --- 1. Base Setup &amp; Door Deduction ---
|
||
IF type == "Basic" THEN
|
||
gap = gap_input
|
||
post_addition = 0
|
||
ELSE IF type == "Allround" THEN
|
||
gap = 11
|
||
post_addition = 51
|
||
END IF
|
||
|
||
IF has_door == TRUE THEN
|
||
deduction = 1124 + gap
|
||
results["door_count"] = 1
|
||
ELSE IF type != "0" THEN
|
||
deduction = 51
|
||
results["door_count"] = 0
|
||
ELSE
|
||
deduction = 0
|
||
results["door_count"] = 0
|
||
END IF
|
||
|
||
remaining_width = total_width - deduction
|
||
test_width = remaining_width
|
||
|
||
// --- 2. Distribute Standard Elements (Greedy Approach) ---
|
||
STANDARD_SIZES = [1507, 1034, 776, 518]
|
||
element_counts = {1507: 0, 1034: 0, 776: 0, 518: 0}
|
||
|
||
FOR EACH size IN STANDARD_SIZES DO
|
||
required_width = size + post_addition
|
||
WHILE test_width &gt;= required_width DO
|
||
element_counts[size] = element_counts[size] + 1
|
||
remaining_width = test_width - required_width
|
||
test_width = remaining_width - gap
|
||
END WHILE
|
||
END FOR
|
||
|
||
// --- 3. Dead Zone Correction ---
|
||
min_special_element = (IF filling_type == 0 THEN 174 ELSE 131) + post_addition
|
||
|
||
IF test_width &gt;= 43 AND test_width &lt;= min_special_element THEN
|
||
smallest_assigned = FIND_SMALLEST_ASSIGNED_ELEMENT(element_counts)
|
||
next_smaller = FIND_NEXT_SMALLER_SIZE(STANDARD_SIZES, smallest_assigned)
|
||
|
||
IF smallest_assigned EXISTS THEN
|
||
element_counts[smallest_assigned] = element_counts[smallest_assigned] - 1
|
||
|
||
IF next_smaller EXISTS THEN
|
||
// Downgrade to next smaller standard element
|
||
element_counts[next_smaller] = element_counts[next_smaller] + 1
|
||
difference = smallest_assigned - next_smaller
|
||
remaining_width = remaining_width + difference
|
||
test_width = test_width + difference
|
||
ELSE
|
||
// Lowest element was 518, remove it completely
|
||
freed_space = post_addition + smallest_assigned + gap
|
||
remaining_width = remaining_width + freed_space
|
||
test_width = test_width + freed_space
|
||
END IF
|
||
END IF
|
||
END IF
|
||
|
||
SAVE element_counts TO results
|
||
test_width = test_width - post_addition
|
||
|
||
// --- 4. Special Element (Sonderelement) Calculation ---
|
||
special_element_width = 0
|
||
test_width_int = FLOOR(test_width)
|
||
|
||
IF test_width_int &lt; 43 THEN
|
||
special_element_width = 0
|
||
ELSE IF test_width_int &gt;= 518 AND test_width_int &lt; 561 THEN
|
||
results["518_count"] = results["518_count"] + 1
|
||
remaining_width = remaining_width - 518 - gap - post_addition
|
||
ELSE IF test_width_int &gt;= 776 AND test_width_int &lt; 819 THEN
|
||
results["776_count"] = results["776_count"] + 1
|
||
remaining_width = remaining_width - 776 - gap - post_addition
|
||
ELSE IF test_width_int &gt;= 131 AND test_width_int &lt; 776 THEN
|
||
// Calculate based on a grid step of 43
|
||
calculated_size = ((test_width_int - 131) / 43) * 43 + 131
|
||
|
||
IF calculated_size == 131 AND min_special_element != 131 + post_addition THEN
|
||
special_element_width = 0 // Min size rule prevents a 131 element
|
||
ELSE
|
||
special_element_width = calculated_size
|
||
END IF
|
||
END IF
|
||
|
||
// --- 5. Final Remainder Output ---
|
||
results["special_element"] = special_element_width
|
||
|
||
IF special_element_width &gt; 0 THEN
|
||
remaining_width = remaining_width - special_element_width - gap - post_addition
|
||
END IF
|
||
|
||
results["final_remainder"] = remaining_width
|
||
|
||
RETURN results
|
||
END FUNCTION
|
||
|
||
FUNCTION determine_parameters_and_generate(start_point, end_point)
|
||
// --- 1. Vererbungs-Weiche (Typ und Füllung ermitteln) ---
|
||
IF start_point.is_pmi == TRUE THEN
|
||
// Vererbung vom Start-PMI (gilt für PMI+Frei und PMI+PMI)
|
||
fence_type = start_point.parent.type
|
||
fence_filling = start_point.parent.filling
|
||
|
||
ELSE IF end_point.is_pmi == TRUE THEN
|
||
// Rückwärtsvererbung vom End-PMI (gilt für Frei+PMI)
|
||
fence_type = end_point.parent.type
|
||
fence_filling = end_point.parent.filling
|
||
|
||
ELSE
|
||
// Beide Punkte frei (Frei+Frei) -&gt; Modales UI-Overlay
|
||
ui_selection = SHOW_MODAL_OVERLAY()
|
||
IF ui_selection == CANCELLED THEN RETURN
|
||
|
||
fence_type = ui_selection.type
|
||
fence_filling = ui_selection.filling
|
||
END IF
|
||
|
||
// --- 2. Geometrie berechnen ---
|
||
total_width = CALCULATE_2D_DISTANCE(start_point, end_point)
|
||
angle = CALCULATE_2D_ANGLE(start_point, end_point)
|
||
|
||
// --- 3. Aufteilung berechnen (Kern-Algorithmus bleibt unverändert) ---
|
||
distribution = calculate_width_distribution(fence_type, FALSE, 0, total_width, fence_filling)
|
||
|
||
// --- 4. Kaskadierende Platzierung triggern ---
|
||
PLACE_FENCE_ELEMENTS(distribution, start_point, angle)
|
||
END FUNCTION</pre>
|
||
</div></div>
|
||
|
||
<h4><a name="NichtZiele%28OutofScope%29"></a>Nicht-Ziele (Out of Scope)</h4>
|
||
|
||
<ul>
|
||
<li><b>Live-Vorschau (Ghosting):</b> Das Rendern einer 3D-Vorschau des Zauns während der Mausbewegung.</li>
|
||
<li><b>Passstücke (Sonderbau):</b> Generierung freier Sonder-Bauteile außerhalb des 43-mm-Rasters.</li>
|
||
<li><b>Spezifikation des Overlays:</b> Das UI des modalen Overlays wird separat spezifiziert.</li>
|
||
</ul>
|
||
|
||
|
||
<hr />
|
||
|
||
<h3><a name="%F0%9F%93%91Akzeptanzkriterien%3A"></a><b>�� Akzeptanzkriterien:</b></h3>
|
||
|
||
<ul>
|
||
<li>Die Vererbungsmatrix wird strikt eingehalten: Das Konfigurations-Overlay öffnet sich <em>ausschließlich</em>, wenn sowohl Start- als auch Endpunkt frei im Raum (Typ 1) liegen.</li>
|
||
<li>Ist der Startpunkt ein PMI, werden inkompatible PMIs im Viewer beim Hovern ignoriert und nicht als Snapping-Ziel angeboten.</li>
|
||
<li>Startet der Zaun frei und endet an einem PMI, übernimmt der Zaun die Parameter des Ziel-Elements fehlerfrei (Rückwärtsvererbung).</li>
|
||
<li>Geometrie wird flach auf der XZ-Ebene berechnet; Höhenunterschiede zwischen den Punkten führen nicht zu schiefen Zäunen.</li>
|
||
<li>Kaskadierendes Verhalten: Bei Verschiebung des Eltern-Bauteils bewegt sich der gesamte Zaun-Verbund mit.</li>
|
||
</ul>
|
||
|
||
|
||
<hr />
|
||
|
||
<h3><a name="%F0%9F%A7%AATestCases%3A"></a><b>�� Test Cases:</b></h3>
|
||
|
||
<ul>
|
||
<li><b><span class="error">&#91;Rückwärtsvererbung&#93;</span></b>: Startpunkt ins Freie klicken -&gt; Endpunkt an PMI eines Basic-Zauns mit Polycarbonat-Füllung snappen -&gt; <em>Erwartetes Ergebnis:</em> Kein Overlay öffnet sich. Es wird sofort ein Basic-Zaun mit Polycarbonat generiert, der an das Ziel snappt.</li>
|
||
<li><b><span class="error">&#91;PMI Typen-Filter&#93;</span></b>: Startpunkt an Allround-PMI klicken -&gt; Maus über ein Basic-PMI bewegen -&gt; <em>Erwartetes Ergebnis:</em> Das Basic-PMI wird nicht gehighlighted und kann nicht als Endpunkt ausgewählt werden.</li>
|
||
<li><b><span class="error">&#91;Overlay-Trigger&#93;</span></b>: Startpunkt frei klicken -&gt; Endpunkt frei klicken -&gt;<em>Erwartetes Ergebnis:</em> Modales Overlay zur Parameterauswahl öffnet sich.</li>
|
||
</ul>
|
||
|
||
|
||
<hr />
|
||
|
||
<h3><a name="%E2%9A%A0%EF%B8%8FEdgeCases%3A%C2%A0"></a><b>⚠️ Edge Cases:</b> </h3>
|
||
|
||
<ul>
|
||
<li><b><span class="error">&#91;Abbruch während Zeichnen&#93;</span></b>: <tt>ESC</tt> oder ein Klick außerhalb des Canvas bricht den Modus nach Klick 1 restlos ab.</li>
|
||
<li><b><span class="error">&#91;Distanz zu kurz&#93;</span></b>: Ist die Gesamtdistanz kleiner als das schmalste verfügbare Rasterelement, führt der Abschluss im Overlay zu einem No-Op (keine Generierung).</li>
|
||
<li><b><span class="error">&#91;Eltern-Löschung&#93;</span></b>: Wird das Bauteil gelöscht, an dessen PMI der Zaun beginnt, verliert das erste Zaunelement seine Typ 2 Bedingung, fällt auf Typ 1 zurück und der Zaun bleibt stehen.</li>
|
||
</ul>
|
||
</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="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>
|
||
<customfieldvalue key="20353"><![CDATA[T‑Shirt‑Aufwand geschätzt]]></customfieldvalue>
|
||
|
||
</customfieldvalues>
|
||
</customfield>
|
||
</customfields>
|
||
</item>
|
||
</channel>
|
||
</rss> |