Swisstopo + OSM Importer + Höhenlinien + Bulk-Op Performance
Swisstopo Iter 3:
- Ortho-Drape: TIN-Mesh aus Terrain-Grid mit per-vertex UVs + PictureFrame-Material
- Project-Cache: TIFs werden neben .3dm gespeichert (SMB-shareable)
- Layer-Restruktur: 80_swisstopo/{Terrain, Luftbild} Sub-Ebenen
- TIFs direkt (kein PNG-Downsampling) für volle Auflösung
- UV-Inset gegen weisse Streifen zwischen Kacheln
- Hoehenlinien (2D, swissALTI3D) auf aktives Geschoss OKFF projiziert
- TIN-Mesh + Schichtenmodell aus Contours (separate Optionen)
- TLM3D entfernt (swisstopo liefert nur GDB/SHP, kein DXF)
OSM Importer (neu):
- rhino/osm.py: Overpass-API-Client
- src/OsmApp.jsx: React-Dialog mit Adresse + Radius + 7 Kategorien
- Strassen/Gebäude/Wasser/Wasserläufe/Parks/Wald/Fusswege (Codes 7101-7107)
- ElementeApp: PillGroup "Importer" mit Swisstopo + OSM Buttons
Sub-Ebenen — rekursiv durch hierarchische Ebenen:
- Visibility-Toggle: slimEbene rekursiv (children bleiben erhalten)
- Settings-Dialog: _find_sublayer_by_code_recursive + _replace_in_tree
- Hatch Auto-Fill: refresh_layer_fills + _fill_signature + _ebene_fill_for_layer
alle rekursiv durch children
- EbenenSettingsApp: flattenEbenen-Helper
Bulk-Op Performance (Delete/Cut/etc.):
- _USER_BULK_CMDS + _BULK_ACTIVE_KEY Sticky-Flag
- CommandBegin: doc.Views.RedrawEnabled = False + Listener-Bail aktiv
- CommandEnd: RedrawEnabled restore + 1× Redraw + Selection-Refresh
- Bail-outs in dimensionen.on_idle/on_select, elemente._on_idle_selection,
gestaltung.on_idle_flush/on_delete
- Verhindert das sichtbare "Runterzählen" pro Element bei Bulk-Delete
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+77
-5
@@ -57,9 +57,19 @@ export default function SwisstopoApp() {
|
||||
// Optionen
|
||||
const [radius, setRadius] = useState(100)
|
||||
const [getBuild, setGetBuild] = useState(true)
|
||||
const [buildVersion, setBuildVersion] = useState('v2') // v2 (stabil) / v3 (beta)
|
||||
const [buildVariant, setBuildVariant] = useState('separated')
|
||||
const [getTerrain, setGetTerrain] = useState(false)
|
||||
const [getOrtho, setGetOrtho] = useState(false)
|
||||
const [getContours, setGetContours] = useState(false)
|
||||
const [getContourTin,setGetContourTin]= useState(false)
|
||||
const [getContourSchicht, setGetContourSchicht] = useState(false)
|
||||
const [contourInt, setContourInt] = useState('2.0')
|
||||
// TLM3D deaktiviert: swisstopo liefert nur GDB/SHP/GPKG — kein DXF.
|
||||
// Rhino kann das nicht nativ importieren; OSM-Importer ist die Alternative
|
||||
// fuer Vektordaten (Strassen/Wasser/Gebaeude).
|
||||
const getTlm = false
|
||||
const tlmKinds = {}
|
||||
const [shift, setShift] = useState(true)
|
||||
const [autoZoom, setAutoZoom] = useState(true)
|
||||
const [replaceExisting, setReplaceExisting] = useState(true)
|
||||
@@ -124,14 +134,21 @@ export default function SwisstopoApp() {
|
||||
|
||||
const handleImport = () => {
|
||||
if (!center) { addLog('Bitte zuerst einen Standort wählen'); return }
|
||||
if (!getBuild && !getTerrain) { addLog('Mindestens Gebäude oder Terrain auswählen'); return }
|
||||
if (!getBuild && !getTerrain && !getContours && !getContourTin && !getContourSchicht && !getTlm) {
|
||||
addLog('Mindestens eine Datenquelle wählen'); return
|
||||
}
|
||||
setLogs([])
|
||||
setRunning(true)
|
||||
setDone(false)
|
||||
const kinds = []
|
||||
if (getBuild) kinds.push('buildings')
|
||||
if (getTerrain) kinds.push('terrain')
|
||||
if (getBuild) kinds.push('buildings')
|
||||
if (getTerrain) kinds.push('terrain')
|
||||
if (getOrtho && getTerrain) kinds.push('ortho')
|
||||
if (getContours) kinds.push('contours')
|
||||
if (getContourTin) kinds.push('contour_tin')
|
||||
if (getContourSchicht)kinds.push('contour_schicht')
|
||||
if (getTlm) kinds.push('tlm')
|
||||
const tlmList = Object.entries(tlmKinds).filter(([, v]) => v).map(([k]) => k)
|
||||
send('RUN_IMPORT', {
|
||||
centerE: center.e,
|
||||
centerN: center.n,
|
||||
@@ -142,7 +159,10 @@ export default function SwisstopoApp() {
|
||||
replaceExisting,
|
||||
clipToBbox,
|
||||
terrainResolution: terrainRes,
|
||||
buildVersion,
|
||||
buildVariant,
|
||||
contourInterval: contourInt,
|
||||
tlmKinds: tlmList,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -237,10 +257,23 @@ export default function SwisstopoApp() {
|
||||
<label style={{ display: 'flex', alignItems: 'center', gap: 6,
|
||||
fontSize: 11, cursor: 'pointer' }}>
|
||||
<input type="checkbox" checked={getBuild} onChange={(e) => setGetBuild(e.target.checked)} />
|
||||
<Icon name="location_city" size={13} /> Bestand-Gebäude (swissBUILDINGS3D 3.0, DWG)
|
||||
<Icon name="location_city" size={13} /> Bestand-Gebäude (swissBUILDINGS3D, DWG)
|
||||
</label>
|
||||
</Field>
|
||||
{getBuild && (
|
||||
<Field label="VERSION"
|
||||
hint="2.0 = stabil, kein Solid/Separated-Split (alle Kategorien auf eigenen DXF-Layern innerhalb einer DWG). 3.0 = neuer, Beta — kann manchmal Probleme mit Variant-Erkennung haben.">
|
||||
<Radio
|
||||
value={buildVersion}
|
||||
options={[
|
||||
{ value: 'v2', label: '2.0 (stabil)' },
|
||||
{ value: 'v3', label: '3.0 (beta)' },
|
||||
]}
|
||||
onChange={setBuildVersion}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
{getBuild && buildVersion === 'v3' && (
|
||||
<Field label="GEBÄUDE-VARIANTE"
|
||||
hint="Solid: ein geschlossenes Solid pro Gebäude (klein, schnell). Separated: Dach/Fassade/Wand als separate Objekte (mehr Detail, ermoeglicht z.B. Dach auszublenden).">
|
||||
<Radio
|
||||
@@ -284,6 +317,45 @@ export default function SwisstopoApp() {
|
||||
</label>
|
||||
</Field>
|
||||
|
||||
<Field label=""
|
||||
hint="2D-Höhenlinien aus dem swissALTI3D-DEM. Werden flach auf die OKFF-Ebene des aktiven Geschosses gelegt — direkt zeichnungstauglich. Unabhängig vom 3D-Mesh.">
|
||||
<label style={{ display: 'flex', alignItems: 'center', gap: 6,
|
||||
fontSize: 11, cursor: 'pointer' }}>
|
||||
<input type="checkbox" checked={getContours}
|
||||
onChange={(e) => setGetContours(e.target.checked)} />
|
||||
<Icon name="terrain" size={13} /> Höhenlinien (2D, auf aktivem Geschoss)
|
||||
</label>
|
||||
</Field>
|
||||
<Field label=""
|
||||
hint="3D-TIN-Mesh aus den Vertices der Höhenlinien — Delaunay-trianguliert. Stilisierter Topo-Look mit weniger Polygonen als das DEM-Mesh.">
|
||||
<label style={{ display: 'flex', alignItems: 'center', gap: 6,
|
||||
fontSize: 11, cursor: 'pointer' }}>
|
||||
<input type="checkbox" checked={getContourTin}
|
||||
onChange={(e) => setGetContourTin(e.target.checked)} />
|
||||
<Icon name="lan" size={13} /> TIN-Mesh aus Höhenlinien
|
||||
</label>
|
||||
</Field>
|
||||
<Field label=""
|
||||
hint="Schichtenmodell: jede geschlossene Höhenlinie wird zur planaren Fläche auf ihrer Z-Höhe — der architektonische Pappmodell-Look.">
|
||||
<label style={{ display: 'flex', alignItems: 'center', gap: 6,
|
||||
fontSize: 11, cursor: 'pointer' }}>
|
||||
<input type="checkbox" checked={getContourSchicht}
|
||||
onChange={(e) => setGetContourSchicht(e.target.checked)} />
|
||||
<Icon name="stacks" size={13} /> Schichtenmodell aus Höhenlinien
|
||||
</label>
|
||||
</Field>
|
||||
{(getContours || getContourTin || getContourSchicht) && (
|
||||
<Field label="HÖHEN-ABSTAND">
|
||||
<Radio value={contourInt}
|
||||
options={[
|
||||
{ value: '1.0', label: '1 m (fein)' },
|
||||
{ value: '2.0', label: '2 m (Standard)' },
|
||||
{ value: '5.0', label: '5 m (grob)' },
|
||||
]}
|
||||
onChange={setContourInt} />
|
||||
</Field>
|
||||
)}
|
||||
|
||||
<SectionLabel>Positionierung</SectionLabel>
|
||||
|
||||
<Field label="ORIGIN"
|
||||
@@ -352,7 +424,7 @@ export default function SwisstopoApp() {
|
||||
background: 'var(--bg-section)',
|
||||
}}>
|
||||
<div style={{ flex: 1, fontSize: 10, color: 'var(--text-muted)' }}>
|
||||
{center ? `Tiles werden gecacht in ~/Library/Caches/Dossier/swisstopo/` : 'Wähle zuerst einen Standort'}
|
||||
{center ? `Tiles werden im Projekt-Ordner neben der .3dm gecacht (Fallback: ~/Library/Caches/Dossier/swisstopo/ wenn ungespeichert)` : 'Wähle zuerst einen Standort'}
|
||||
</div>
|
||||
<button className="btn-text" onClick={() => send('CANCEL', {})}
|
||||
disabled={running}>
|
||||
|
||||
Reference in New Issue
Block a user