@@ -104,6 +104,7 @@ const app = {
104104 // "render every chiplet" (single-chip designs).
105105 visibleChiplets : null ,
106106 useTrueZ : getCookie ( 'or_use_true_z' ) === '1' ,
107+ showDbu : getCookie ( 'or_show_dbu' ) === '1' ,
107108 selectableLayers : new Set ( ) ,
108109 heatMapData : null ,
109110 activeHeatMap : '' ,
@@ -114,6 +115,24 @@ const app = {
114115 getDbuPerMicron ( ) {
115116 return this . techData ?. dbu_per_micron || 1000 ;
116117 } ,
118+ // Format a DBU value as a display string, respecting the showDbu setting.
119+ // Mirrors Qt GUI's MainWindow::convertDBUToString.
120+ formatDbu ( value , addUnits = false ) {
121+ if ( this . showDbu ) return String ( Math . round ( value ) ) ;
122+ const dbuPerUm = this . getDbuPerMicron ( ) ;
123+ const precision = Math . ceil ( Math . log10 ( dbuPerUm ) ) ;
124+ const um = ( value / dbuPerUm ) . toFixed ( precision ) ;
125+ return addUnits ? um + ' \u00b5m' : um ;
126+ } ,
127+ // Format a distance (always positive) with auto-scaling units.
128+ formatDistance ( dbuLength ) {
129+ if ( this . showDbu ) return String ( Math . round ( dbuLength ) ) ;
130+ const dbuPerUm = this . getDbuPerMicron ( ) ;
131+ const um = dbuLength / dbuPerUm ;
132+ if ( um >= 1000 ) return ( um / 1000 ) . toFixed ( 3 ) + ' mm' ;
133+ if ( um >= 1 ) return um . toFixed ( 3 ) + ' um' ;
134+ return ( um * 1000 ) . toFixed ( 1 ) + ' nm' ;
135+ } ,
117136} ;
118137
119138const visibility = {
@@ -469,11 +488,7 @@ function createLayoutViewer(container) {
469488 const { dbuX, dbuY } = latLngToDbu (
470489 e . latlng . lat , e . latlng . lng , app . designScale , app . designMaxDXDY ,
471490 app . designOriginX , app . designOriginY ) ;
472- const dbuPerUm = app . getDbuPerMicron ( ) ;
473- const precision = Math . ceil ( Math . log10 ( dbuPerUm ) ) ;
474- const xUm = ( dbuX / dbuPerUm ) . toFixed ( precision ) ;
475- const yUm = ( dbuY / dbuPerUm ) . toFixed ( precision ) ;
476- coordBar . textContent = `X: ${ xUm } Y: ${ yUm } ` ;
491+ coordBar . textContent = `X: ${ app . formatDbu ( dbuX ) } Y: ${ app . formatDbu ( dbuY ) } ` ;
477492 } ) ;
478493 app . map . on ( 'mouseout' , ( ) => { app . lastMouseLatLng = null ; } ) ;
479494
@@ -488,41 +503,49 @@ function createLayoutViewer(container) {
488503 scaleBarLabel . className = 'scale-bar-label' ;
489504 scaleBar . appendChild ( scaleBarLabel ) ;
490505
506+ // Round to the nearest 1/2/5 × 10^n value (e.g. 1, 2, 5, 10, 20, …).
507+ function niceRound ( value ) {
508+ const mag = Math . pow ( 10 , Math . floor ( Math . log10 ( value ) ) ) ;
509+ const residual = value / mag ;
510+ if ( residual < 1.5 ) return 1 * mag ;
511+ if ( residual < 3.5 ) return 2 * mag ;
512+ if ( residual < 7.5 ) return 5 * mag ;
513+ return 10 * mag ;
514+ }
515+
491516 function updateScaleBar ( ) {
492517 if ( ! app . designScale || ! visibility . scale_bar ) {
493518 scaleBar . style . display = 'none' ;
494519 return ;
495520 }
496521 scaleBar . style . display = '' ;
497522
498- const dbuPerUm = app . techData ?. dbu_per_micron || 1000 ;
499523 // Pixels per DBU at current zoom: designScale * 2^zoom.
500524 const zoom = app . map . getZoom ( ) ;
501525 const pxPerDbu = app . designScale * Math . pow ( 2 , zoom ) ;
502- const pxPerUm = pxPerDbu * dbuPerUm ;
503526
504527 // Target bar width: ~15% of the map container width.
505528 const containerWidth = app . map . getContainer ( ) . clientWidth || 400 ;
506529 const targetPx = containerWidth * 0.15 ;
507- const targetUm = targetPx / pxPerUm ;
508-
509- // Pick a nice round number: 1, 2, 5, 10, 20, 50, ...
510- const mag = Math . pow ( 10 , Math . floor ( Math . log10 ( targetUm ) ) ) ;
511- const residual = targetUm / mag ;
512- let niceUm ;
513- if ( residual < 1.5 ) niceUm = 1 * mag ;
514- else if ( residual < 3.5 ) niceUm = 2 * mag ;
515- else if ( residual < 7.5 ) niceUm = 5 * mag ;
516- else niceUm = 10 * mag ;
517-
518- const barPx = Math . round ( niceUm * pxPerUm ) ;
519-
520- // Format with appropriate units.
521- let label ;
522- if ( niceUm >= 1000 ) label = ( niceUm / 1000 ) + ' mm ' ;
523- else if ( niceUm >= 1 ) label = niceUm + ' \u00b5m ' ;
524- else if ( niceUm >= 0.001 ) label = ( niceUm * 1000 ) + ' nm ' ;
525- else label = ( niceUm * 1e6 ) + ' pm' ;
530+
531+ let barPx , label ;
532+ if ( app . showDbu ) {
533+ const niceDbu = Math . max ( 1 , niceRound ( targetPx / pxPerDbu ) ) ;
534+ barPx = Math . round ( niceDbu * pxPerDbu ) ;
535+ label = String ( Math . round ( niceDbu ) ) ;
536+ } else {
537+ const dbuPerUm = app . techData ?. dbu_per_micron || 1000 ;
538+ const pxPerUm = pxPerDbu * dbuPerUm ;
539+ const niceUm = niceRound ( targetPx / pxPerUm ) ;
540+
541+ barPx = Math . round ( niceUm * pxPerUm ) ;
542+
543+ // Format with appropriate units.
544+ if ( niceUm >= 1000 ) label = ( niceUm / 1000 ) + ' mm' ;
545+ else if ( niceUm >= 1 ) label = niceUm + ' \u00b5m ' ;
546+ else if ( niceUm >= 0.001 ) label = ( niceUm * 1000 ) + ' nm ' ;
547+ else label = ( niceUm * 1e6 ) + ' pm ' ;
548+ }
526549
527550 scaleBarLine . style . width = barPx + 'px' ;
528551 scaleBarLabel . textContent = label ;
@@ -654,6 +677,7 @@ const highlightBBox = inspector.highlightBBox;
654677const pulseHighlight = inspector . pulseHighlight ;
655678app . updateInspector = updateInspector ;
656679app . navigateInspector = inspector . navigateInspector ;
680+ app . refreshInspector = inspector . refreshInspector ;
657681
658682function createBrowser ( container ) {
659683 new HierarchyBrowser ( container , app , redrawAllLayers ) ;
@@ -924,6 +948,19 @@ app.toggleTheme = function() {
924948 if ( app . clockTreeWidget ) app . clockTreeWidget . render ( ) ;
925949} ;
926950
951+ app . toggleShowDbu = function ( ) {
952+ app . showDbu = ! app . showDbu ;
953+ setCookie ( 'or_show_dbu' , app . showDbu ? '1' : '0' ) ;
954+ // Re-render rulers so their labels update.
955+ if ( app . rulerManager ) app . rulerManager . _rerenderAll ( ) ;
956+ // Re-render hierarchy browser if present.
957+ if ( app . hierarchyBrowser ) app . hierarchyBrowser . _render ( ) ;
958+ // Update scale bar.
959+ if ( app . updateScaleBar ) app . updateScaleBar ( ) ;
960+ // Re-request inspector properties with new formatting.
961+ if ( app . refreshInspector ) app . refreshInspector ( ) ;
962+ } ;
963+
927964// ─── Menu Bar ────────────────────────────────────────────────────────────────
928965
929966createMenuBar ( app ) ;
@@ -1099,6 +1136,7 @@ app.websocketManager.readyPromise.then(async () => {
10991136 zoom : Math . round ( app . map . getZoom ( ) ) ,
11001137 visible_layers : [ ...app . visibleLayerNames ] ,
11011138 selectable_layers : [ ...app . selectableLayers ] ,
1139+ use_dbu : app . showDbu ,
11021140 ...vf ,
11031141 } ;
11041142 if ( e . originalEvent && e . originalEvent . shiftKey ) {
0 commit comments