place method

Future<UArPlacedItem?> place(
  1. UArHitResult hit, {
  2. UArPlaceable? item,
})

Places item (or the selected one) on hit.

Implementation

Future<UArPlacedItem?> place(UArHitResult hit, {UArPlaceable? item}) async {
  final UArPlaceable? placeable = item ?? currentItem;
  if (placeable == null || busy) return null;
  if (!_matches(hit, placeable.surface)) return null;
  final int count = placed.where((UArPlacedItem p) => p.item.id == placeable.id).length;
  if (placeable.maxCount > 0 && count >= placeable.maxCount) {
    final UArPlacedItem existing = placed.firstWhere((UArPlacedItem p) => p.item.id == placeable.id);
    await controller.updateAnchor(existing.anchorId, placementPose(hit));
    return existing;
  }
  if (_o.maxPlacements > 0 && placed.length >= _o.maxPlacements) {
    if (!_o.replaceWhenFull) return null;
    await remove(placed.first.nodeId);
  }
  setState(() => busy = true);
  try {
    final UArAnchor anchor = await controller.addAnchor(placementPose(hit), trackableId: hit.trackableId);
    final String nodeId = controller.newId("item");
    final UArNode node = placeable.build(nodeId).copyWith(anchorId: anchor.id);
    final UArNodeInfo info = await controller.addNode(node);
    if (hit.isWall && node.type == UArNodeType.model) {
      final UArVector3 offset = UArVector3(0, 0, max(0.005, (info.size.x.abs() + info.size.z.abs()) / 4));
      _offsets[nodeId] = offset;
      await controller.transformNode(nodeId, position: offset);
    }
    final UArPlacedItem result = UArPlacedItem(nodeId: nodeId, anchorId: anchor.id, item: placeable, hit: hit, info: info);
    placed.add(result);
    if (_o.haptics) unawaited(HapticFeedback.lightImpact());
    if (_o.selectOnPlace) selectedNode = nodeId;
    if (_o.showGestureHint && !_gestureHintShown) {
      _gestureHintShown = true;
      _showGestureHint = true;
      Future<void>.delayed(const Duration(seconds: 4), () {
        if (mounted) setState(() => _showGestureHint = false);
      });
    }
    widget.onPlaced?.call(result);
    return result;
  } on UArException catch (error) {
    widget.onError?.call(error);
    return null;
  } finally {
    if (mounted) setState(() => busy = false);
  }
}