@@ -137,6 +137,9 @@ export type EditorFunctionGenericOutput = {|
137137 // Default size, origin and center of the object(s) being operated on, keyed by object name:
138138 objectSizeInfo ?: { [ string ] : ObjectSizeInfo | null } ,
139139
140+ // Explanation of the coordinate semantics of `instances` positions:
141+ positionSemantics ?: string ,
142+
140143 hints ?: Array < HintEntry > ,
141144
142145 // Set to true when the function call was aborted mid-execution (e.g. the AI
@@ -381,6 +384,45 @@ const injectObjectSizeInfo = (
381384 return output ;
382385} ;
383386
387+ const INSTANCE_POSITION_SEMANTICS_MESSAGE =
388+ 'Each instance x;y;z is its origin, NOT its center. Unless `objectSizeInfo` indicates a custom origin, the origin is the minimum corner: an instance occupies x to x+width, y to y+height and (in 3D) z to z+depth, so its center is at position + size/2. To center an instance A on top of an instance B: A.x = B.x + (B.width - A.width)/2, A.y = B.y + (B.height - A.height)/2, A.z = B.z + B.depth.' ;
389+
390+ const getOccupiedSpaceDescription = (
391+ position : $ReadOnlyArray < number > ,
392+ size : $ReadOnlyArray < number > ,
393+ objectSizeInfo : ObjectSizeInfo | null
394+ ) : string => {
395+ const round = ( value : number ) => Math . round ( value * 100 ) / 100 ;
396+ const axes = [ 'X' , 'Y' , 'Z' ] ;
397+ const originOffsets = [ 0 , 0 , 0 ] ;
398+ if ( objectSizeInfo ) {
399+ const defaultSizes = [
400+ objectSizeInfo . width ,
401+ objectSizeInfo . height ,
402+ objectSizeInfo . depth ,
403+ ] ;
404+ const origins = [
405+ objectSizeInfo . originX ,
406+ objectSizeInfo . originY ,
407+ objectSizeInfo . originZ ,
408+ ] ;
409+ for ( let i = 0 ; i < size . length ; i ++ ) {
410+ const defaultSize = defaultSizes [ i ] ;
411+ const origin = origins [ i ] ;
412+ // Origin offsets are given for the default size - scale them to the actual size.
413+ if ( origin && defaultSize ) {
414+ originOffsets [ i ] = origin * ( size [ i ] / defaultSize ) ;
415+ }
416+ }
417+ }
418+ return size
419+ . map ( ( sizeOnAxis , i ) => {
420+ const min = position [ i ] - originOffsets [ i ] ;
421+ return `${ axes [ i ] } ${ round ( min ) } to ${ round ( min + sizeOnAxis ) } ` ;
422+ } )
423+ . join ( ', ' ) ;
424+ } ;
425+
384426const makeGenericSuccess = ( message : string ) : EditorFunctionGenericOutput => ( {
385427 success : true ,
386428 message,
@@ -2488,6 +2530,7 @@ const describeInstances: EditorFunction = {
24882530 const initialInstances = layout . getInitialInstances ( ) ;
24892531
24902532 const instances = [ ] ;
2533+ const objectSizeInfoByName : { [ string ] : ObjectSizeInfo | null } = { } ;
24912534
24922535 // For each layer
24932536 mapFor ( 0 , layout . getLayersCount ( ) , i => {
@@ -2511,8 +2554,15 @@ const describeInstances: EditorFunction = {
25112554 object = globalObjects . getObject ( objectName ) ;
25122555 }
25132556
2514- const defaultSize = object
2557+ const sizeInfo = object
25152558 ? getObjectSizeInfo ( object , project , PixiResourcesLoader )
2559+ : null ;
2560+ if ( object && ! ( objectName in objectSizeInfoByName ) ) {
2561+ objectSizeInfoByName [ objectName ] = sizeInfo ;
2562+ }
2563+
2564+ const defaultSize = object
2565+ ? sizeInfo
25162566 : { width : 0 , height : 0 , depth : 0 } ;
25172567
25182568 const width = instance . hasCustomSize ( )
@@ -2537,6 +2587,8 @@ const describeInstances: EditorFunction = {
25372587 // Replace persistentUuid by id:
25382588 persistentUuid : undefined ,
25392589 id : instance . getPersistentUuid ( ) . slice ( 0 , 10 ) ,
2590+ // The serializer omits z when it's 0 - always expose it for 3D objects:
2591+ z : depth !== null ? instance . getZ ( ) : undefined ,
25402592 // Actual computed dimensions (accounting for default size when no custom size is set):
25412593 width,
25422594 height,
@@ -2550,20 +2602,16 @@ const describeInstances: EditorFunction = {
25502602 ) ;
25512603 } ) ;
25522604
2605+ const result : EditorFunctionGenericOutput = {
2606+ success : true ,
2607+ instances : instances ,
2608+ instancesForSceneNamed : scene_name ,
2609+ positionSemantics : INSTANCE_POSITION_SEMANTICS_MESSAGE ,
2610+ } ;
25532611 if ( objectNames . size > 0 ) {
2554- return {
2555- success : true ,
2556- instances : instances ,
2557- instancesForSceneNamed : scene_name ,
2558- instancesOnlyForObjectsNamed : [ ...objectNames ] . sort ( ) . join ( ',' ) ,
2559- } ;
2560- } else {
2561- return {
2562- success : true ,
2563- instances : instances ,
2564- instancesForSceneNamed : scene_name ,
2565- } ;
2612+ result . instancesOnlyForObjectsNamed = [ ...objectNames ] . sort ( ) . join ( ',' ) ;
25662613 }
2614+ return injectObjectSizeInfo ( result , objectSizeInfoByName ) ;
25672615 } ,
25682616 modifiesProject : false ,
25692617} ;
@@ -3028,6 +3076,22 @@ const put2dInstances: EditorFunction = {
30283076 attrs . push ( `opacity ${ instancesOpacity } /255` ) ;
30293077 if ( instances_z_order !== null )
30303078 attrs . push ( `z-order ${ instances_z_order } ` ) ;
3079+ const effectiveSize = instancesSize
3080+ ? instancesSize
3081+ : objectSizeInfo &&
3082+ objectSizeInfo . width !== null &&
3083+ objectSizeInfo . height !== null
3084+ ? [ objectSizeInfo . width , objectSizeInfo . height ]
3085+ : null ;
3086+ if ( brush_kind === 'point' && effectiveSize ) {
3087+ attrs . push (
3088+ `origin at this position, each occupies ${ getOccupiedSpaceDescription (
3089+ brushPosition ,
3090+ effectiveSize ,
3091+ objectSizeInfo
3092+ ) } `
3093+ ) ;
3094+ }
30313095 changes . push (
30323096 `Created ${ newInstancesCount } new instance${
30333097 newInstancesCount > 1 ? 's' : ''
@@ -3595,6 +3659,23 @@ const put3dInstances: EditorFunction = {
35953659 instancesRotationArray [ 1 ]
35963660 } °, ${ instancesRotationArray [ 2 ] } °)`
35973661 ) ;
3662+ const effectiveSize = instancesSizeArray
3663+ ? instancesSizeArray
3664+ : objectSizeInfo &&
3665+ objectSizeInfo . width !== null &&
3666+ objectSizeInfo . height !== null &&
3667+ objectSizeInfo . depth !== null
3668+ ? [ objectSizeInfo . width , objectSizeInfo . height , objectSizeInfo . depth ]
3669+ : null ;
3670+ if ( brush_kind === 'point' && effectiveSize ) {
3671+ attrs . push (
3672+ `origin at this position, each occupies ${ getOccupiedSpaceDescription (
3673+ brushPosition ,
3674+ effectiveSize ,
3675+ objectSizeInfo
3676+ ) } `
3677+ ) ;
3678+ }
35983679 changes . push (
35993680 `Created ${ newInstancesCount } new instance${
36003681 newInstancesCount > 1 ? 's' : ''
0 commit comments