import { Matrix3d , Point3d , Transform } from "@itwin/core-geometry" ; import { IModelApp , ModelDisplayTransformProvider , Tool } from "@itwin/core-frontend" ; import { parseArgs } from "@itwin/frontend-devtools" ; class DisplayScaleTransformProvider implements ModelDisplayTransformProvider { public constructor ( private readonly _models , private readonly _scaleTransform ) { } public getModelDisplayTransform ( modelId , baseTransform ) { if ( ! this . _models . has ( modelId ) ) return baseTransform ; return this . _scaleTransform . multiplyTransformTransform ( baseTransform ) ; } public get transform ( ) : Transform { return this . _scaleTransform . clone ( ) ; } } /** Apply a display transform to all currently displayed models. */ export class ApplyModelDisplayScaleTool extends Tool { public static override toolId = "ApplyModelDisplayScale" ; public static override get minArgs ( ) { return 0 ; } public static override get maxArgs ( ) { return 3 ; } public override async run ( scale ) { const vp = IModelApp . viewManager . selectedView ; if ( ! vp ) return false ; const f = vp . getWorldFrustum ( ) ; if ( undefined !== vp . view . modelDisplayTransformProvider && vp . view . modelDisplayTransformProvider instanceof DisplayScaleTransformProvider ) { const t = vp . view . modelDisplayTransformProvider . transform ; const sx = t . matrix . getColumn ( 0 ) . magnitude ( ) ; const sy = t . matrix . getColumn ( 1 ) . magnitude ( ) ; const sz = t . matrix . getColumn ( 2 ) . magnitude ( ) ; const inverseMax = 1.0 / Math . max ( sx , sy , sz ) ; const scaleFrustumInvTf = Transform . createRefs ( Point3d . createZero ( ) , Matrix3d . createScale ( inverseMax , inverseMax , inverseMax ) ) ; f . multiply ( scaleFrustumInvTf ) ; } let scl ; let maxScale = 1.0 ; if ( scale . isAlmostEqual ( Point3d . create ( 1.0 , 1.0 , 1.0 ) ) ) { if ( undefined !== vp . view . modelDisplayTransformProvider ) { vp . view . modelDisplayTransformProvider = undefined ; } else { return false ; } scl = Matrix3d . createIdentity ( ) ; } else { scl = Matrix3d . createScale ( scale . x , scale . y , scale . z ) ; maxScale = Math . max ( scale . y , scale . y , scale . z ) ; } const models = new Set < string > ( ) ; vp . view . forEachModel ( ( model ) => models . add ( model . id ) ) ; const sclTf = Transform . createRefs ( Point3d . createZero ( ) , scl ) ; const tp = new DisplayScaleTransformProvider ( models , sclTf ) ; vp . setModelDisplayTransformProvider ( tp ) ; const scaleFrustumTf = Transform . createRefs ( Point3d . createZero ( ) , Matrix3d . createScale ( maxScale , maxScale , maxScale ) ) ; f . multiply ( scaleFrustumTf ) ; vp . setupViewFromFrustum ( f ) ; return true ; } public override async parseAndRun ( ... input ) { const args = parseArgs ( input ) ; const scale = new Point3d ( args . getFloat ( "x" ) ?? 1.0 , args . getFloat ( "y" ) ?? 1.0 , args . getFloat ( "z" ) ?? 1.0 ) ; return this . run ( scale ) ; } }