Skip to content

Commit

Permalink
Propagate origin displacements of child structures to parent (#2150)
Browse files Browse the repository at this point in the history
Builds upon #2127 to fix the remaining issues with #1826.

If a structure incorporates sub-placements entailing northwesterly offsets, its "coordinate origin" will be shifted relative to the top-left cell in the grid.  This updated coordinate origin should be propagated to parent structures for use when placing it.  This includes placement of the main "area" onto the toplevel world map.  This is essential when composing a large scene that needs to line up with features generated by the DSL.

Another bug fixed in this PR involved incorrect "area" computation within sibling placements when both a "northward" and "westward" offset were used; existing tests only covered each of these directions separately.

## Changes in this PR

* Refactoring for readability
* Improved naming
    * Fixed typo `padSouthwest` -> `padNorthwest`
* Export some functions for unit tests
* Utilize propagated coordinate offset in `WorldDescription`

## Testing

### Unit tests

```
scripts/test/run-tests.sh swarm-unit --test-options '--pattern "Overlay"'
```

### Scenarios

```
scripts/play.sh -i data/scenarios/Testing/1780-structure-merge-expansion/coordinate-offset-propagation.yaml --hide-goal
```
| Before | After |
| --- | --- |
| ![Screenshot from 2024-09-22 19-54-13](https://github.com/user-attachments/assets/b7d79232-7435-4cdf-a586-4df4df5cd978) | ![Screenshot from 2024-09-22 19-50-10](https://github.com/user-attachments/assets/4c6a248c-153c-4461-9012-526f59d1ce35) |

```
scripts/play.sh -i data/scenarios/Testing/1780-structure-merge-expansion/simultaneous-north-and-west-offset.yaml --hide-goal
```


| Before | After |
| --- | --- |
| ![Screenshot from 2024-09-22 19-53-50](https://github.com/user-attachments/assets/2049c905-c283-4c43-adc2-f355ea055ada) | ![Screenshot from 2024-09-22 19-53-07](https://github.com/user-attachments/assets/d120d084-31c6-4a67-855d-e08043a93891) |
  • Loading branch information
kostmo authored Sep 23, 2024
1 parent 5c485ad commit b2983b9
Show file tree
Hide file tree
Showing 13 changed files with 443 additions and 69 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
nonoverlapping-structure-merge.yaml
root-map-expansion.yaml
structure-composition.yaml
sequential-placement.yaml
sequential-placement.yaml
coordinate-offset-propagation.yaml
simultaneous-north-and-west-offset.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
version: 1
name: Structure coordinate offset propagation
author: Karl Ostmo
description: |
If a structure incorporates subplacements
entailing negative offsets, its coordinate origin must be shifted.
The updated coordinate origin should be propagated to parent structures
and utilized to offset placement.
robots:
- name: base
dir: north
loc: [0, 3]
objectives:
- goal:
- Enjoy the view.
condition: |
return true
solution: |
noop
known: [boulder, log, pixel (R), pixel (G), pixel (B), gold]
world:
structures:
- name: micro
structure:
mask: '.'
palette:
'x': [stone, gold]
map: |
xx
- name: block
structure:
mask: '.'
palette:
'x': [stone, pixel (R)]
map: |
xx
xx
- name: master
structure:
mask: '.'
palette:
'x': [stone, pixel (B)]
placements:
- src: block
offset: [0, 1]
- src: micro
offset: [-2, 0]
map: |
..x
..x
..x
- name: final
structure:
mask: '.'
palette:
'x': [stone, pixel (G)]
placements:
- src: master
map: |
x
x
x
x
dsl: |
overlay
[ {grass}
, mask (y > -4 && y < 4 || x > -4 && x < 4) {stone}
, mask (y > -2 && y < 2 || x > -2 && x < 2) {ice}
, mask (y > -1 && y < 1 || x > -1 && x < 1) {dirt}
]
mask: '.'
placements:
- src: final
offset: [0, 0]
upperleft: [0, 0]
map: ""
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ objectives:
- Must have 3 of each color visible
condition: |
def countColor = \e.
resonate e ((0, 0), (10, -5));
resonate e ((-6, 0), (4, -4));
end;
as base {
Expand Down Expand Up @@ -87,7 +87,7 @@ world:
mask: '.'
placements:
- src: block
offset: [0, -1]
offset: [0, -2]
upperleft: [0, 0]
dsl: |
{grass}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
version: 1
name: Northwest sibling structure coordinate offsets
author: Karl Ostmo
description: |
Make sure that the second sibling is displayed correctly when there
is a simultaneous negative-x and positive-y offset on the first sibling.
robots:
- name: base
dir: north
loc: [0, 2]
objectives:
- goal:
- Enjoy the view.
condition: |
return true
solution: |
noop
known: [pixel (R), gold]
world:
structures:
- name: micro
structure:
mask: '.'
palette:
'x': [stone, gold]
map: |
x
- name: block
structure:
mask: '.'
palette:
'x': [stone, pixel (R)]
map: |
xx
xx
- name: master
structure:
mask: '.'
placements:
- src: micro
offset: [-1, 1]
- src: block
map: ""
dsl: |
overlay
[ {grass}
, mask (y > -4 && y < 4 || x > -4 && x < 4) {stone}
, mask (y > -2 && y < 2 || x > -2 && x < 2) {ice}
, mask (y > -1 && y < 1 || x > -1 && x < 1) {dirt}
]
mask: '.'
placements:
- src: master
offset: [0, 0]
upperleft: [0, 0]
map: ""
2 changes: 1 addition & 1 deletion data/test/standalone-topography/circle-and-crosses.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,5 @@ placements:
orient:
up: west
- src: disc
offset: [8, -8]
offset: [5, -8]
map: ""
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,7 @@ instance FromJSONE WorldParseDependencies WorldDescription where
let placedStructures =
map (offsetLoc $ coerce ul) staticStructurePlacements

-- Override upper-left corner with explicit location
let area = mergedGrid {gridPosition = ul}

let area = modifyLoc ((ul .+^) . asVector) mergedGrid
return $ WorldDescription {..}

------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion src/swarm-topography/Swarm/Game/Location.hs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ euclidean p1 p2 = norm (fromIntegral <$> (p2 .-. p1))

-- | Converts a 'Point' to a vector offset from the 'origin'.
asVector :: Location -> V2 Int32
asVector loc = loc .-. origin
asVector (P vec) = vec

-- | Get all the locations that are within a certain manhattan
-- distance from a given location.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ data AreaDimensions = AreaDimensions
{ rectWidth :: Int32
, rectHeight :: Int32
}
deriving (Show, Eq)

getGridDimensions :: Grid a -> AreaDimensions
getGridDimensions g = getAreaDimensions $ getRows g
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
-- as well as logic for combining them.
module Swarm.Game.Scenario.Topography.Structure.Assembly (
mergeStructures,

-- * Exposed for unit tests:
foldLayer,
)
where

Expand Down Expand Up @@ -63,30 +66,15 @@ mergeStructures ::
Parentage Placement ->
PStructure (Maybe a) ->
Either Text (MergedStructure (Maybe a))
mergeStructures inheritedStrucDefs parentPlacement (Structure origArea subStructures subPlacements subWaypoints) = do
mergeStructures inheritedStrucDefs parentPlacement baseStructure = do
overlays <-
left (elaboratePlacement parentPlacement <>) $
mapM (validatePlacement structureMap) subPlacements

let wrapPlacement (Placed z ns) =
LocatedStructure
(name ns)
(up $ orient structPose)
(offset structPose)
where
structPose = structurePose z

wrappedOverlays =
map wrapPlacement $
filter (\(Placed _ ns) -> isRecognizable ns) overlays

-- NOTE: Each successive overlay may alter the coordinate origin.
-- We make sure this new origin is propagated to subsequent sibling placements.
foldlM
(flip $ overlaySingleStructure structureMap)
(MergedStructure origArea wrappedOverlays originatedWaypoints)
overlays
foldLayer structureMap origArea overlays originatedWaypoints
where
Structure origArea subStructures subPlacements subWaypoints = baseStructure

originatedWaypoints = map (Originated parentPlacement) subWaypoints

-- deeper definitions override the outer (toplevel) ones
Expand All @@ -95,6 +83,32 @@ mergeStructures inheritedStrucDefs parentPlacement (Structure origArea subStruct
(M.fromList $ map (name &&& id) subStructures)
inheritedStrucDefs

-- | NOTE: Each successive overlay may alter the coordinate origin.
-- We make sure this new origin is propagated to subsequent sibling placements.
foldLayer ::
M.Map StructureName (NamedStructure (Maybe a)) ->
PositionedGrid (Maybe a) ->
[Placed (Maybe a)] ->
[Originated Waypoint] ->
Either Text (MergedStructure (Maybe a))
foldLayer structureMap origArea overlays originatedWaypoints =
foldlM
(flip $ overlaySingleStructure structureMap)
(MergedStructure origArea wrappedOverlays originatedWaypoints)
overlays
where
wrappedOverlays =
map wrapPlacement $
filter (\(Placed _ ns) -> isRecognizable ns) overlays

wrapPlacement (Placed z ns) =
LocatedStructure
(name ns)
(up $ orient structPose)
(offset structPose)
where
structPose = structurePose z

-- * Grid manipulation

overlayGridExpanded ::
Expand All @@ -105,14 +119,13 @@ overlayGridExpanded ::
overlayGridExpanded
baseGrid
(Pose yamlPlacementOffset orientation)
-- NOTE: The '_childAdjustedOrigin' is the sum of origin adjustments
-- to completely assemble some substructure. However, we discard
-- this when we place a substructure into a new base grid.
(PositionedGrid _childAdjustedOrigin overlayArea) =
-- The 'childAdjustedOrigin' is the sum of origin adjustments
-- to completely assemble some substructure.
(PositionedGrid childAdjustedOrigin overlayArea) =
baseGrid <> positionedOverlay
where
reorientedOverlayCells = applyOrientationTransform orientation overlayArea
placementAdjustedByOrigin = gridPosition baseGrid .+^ asVector yamlPlacementOffset
placementAdjustedByOrigin = childAdjustedOrigin .+^ asVector yamlPlacementOffset
positionedOverlay = PositionedGrid placementAdjustedByOrigin reorientedOverlayCells

-- * Validation
Expand Down
Loading

0 comments on commit b2983b9

Please sign in to comment.