using System; using System.Linq; using System.Windows.Input; using System.Windows.Media.Media3D; using devDept.Eyeshot; using devDept.Eyeshot.Control; using devDept.Eyeshot.Entities; using devDept.Geometry; using WpfEngineeringSketch.Models.Scene; using WpfEngineeringSketch.Rendering; using WpfEngineeringSketch.ViewModels; namespace WpfEngineeringSketch.Tools3D { public class PlaceTool3D : I3DTool { public string Name => "Place"; private SceneObject? _ghostObject; public void Activate(MainViewModel vm) { _ghostObject = new SceneObject { Type = vm.SelectedBlockType, Position = new System.Windows.Media.Media3D.Point3D(0, 0, 0), }; vm.Objects.Add(_ghostObject); if (vm.SelectedBlockType == BlockType.CMUWall) { UpdateSmartIndicators(vm); } } public void Deactivate(MainViewModel vm) { if (_ghostObject != null) { vm.Objects.Remove(_ghostObject); _ghostObject = null; } } public void OnMouseDown(MainViewModel vm, Design design, MouseButtonEventArgs e) { if (e.ChangedButton == System.Windows.Input.MouseButton.Left) { var mousePos = e.GetPosition(design); var point = new System.Drawing.Point((int)mousePos.X, (int)mousePos.Y); // 0. Check for UI Indicator Click (CMU Wall smart placement) if (vm.SelectedBlockType == BlockType.CMUWall) { var item = design.GetItemUnderMouseCursor(point); if (item != null && item.Item is Entity entity) { var obj = SceneBinder.GetSceneObjectFromEntity(entity); if (obj != null && obj.Type == BlockType.UIIndicator) { var wallPos = new System.Windows.Media.Media3D.Point3D(obj.Position.X, obj.Position.Y - 2, obj.Position.Z); var newWall = new SceneObject { Type = BlockType.CMUWall, Position = wallPos, }; var gridLine = vm.Objects.FirstOrDefault(o => o.Type == BlockType.GridLine && (o.Position - wallPos).Length < 0.1); if (gridLine != null) newWall.Rotation = gridLine.Rotation; vm.Objects.Add(newWall); vm.Objects.Remove(obj); // Optimization: Update indicators UpdateSmartIndicators(vm); return; } } } // Normal Place Logic if (_ghostObject != null) { // Create concrete object // We need current position. Calculated in OnMouseMove, or re-calc here. // Recalculate for safety design.ScreenToPlane(point, Plane.XY, out devDept.Geometry.Point3D worldPoint); // Simple snap double snap = 0.5; double x = Math.Round(worldPoint.X / snap) * snap; double z = Math.Round(worldPoint.Z / snap) * snap; double y = 0; // Flat on ground usually double yOffset = GetYOffset(vm.SelectedBlockType); y += yOffset; var newObj = new SceneObject { Type = _ghostObject.Type, Position = new System.Windows.Media.Media3D.Point3D(x, y, z), Rotation = _ghostObject.Rotation, Scale = _ghostObject.Scale }; vm.Objects.Add(newObj); } } } public void OnMouseMove(MainViewModel vm, Design design, MouseEventArgs e) { if (_ghostObject != null) { var mousePos = e.GetPosition(design); design.ScreenToPlane(new System.Drawing.Point((int)mousePos.X, (int)mousePos.Y), Plane.XY, out devDept.Geometry.Point3D worldPoint); if (worldPoint != null) { double snap = 0.5; double x = Math.Round(worldPoint.X / snap) * snap; double z = Math.Round(worldPoint.Z / snap) * snap; double y = 0; double yOffset = GetYOffset(vm.SelectedBlockType); y += yOffset; _ghostObject.Position = new System.Windows.Media.Media3D.Point3D(x, y, z); if (_ghostObject.Type != vm.SelectedBlockType) { _ghostObject.Type = vm.SelectedBlockType; } } } } public void OnMouseUp(MainViewModel vm, Design design, MouseButtonEventArgs e) { } private double GetYOffset(BlockType type) { switch (type) { case BlockType.Cube: return 0.5; case BlockType.Column: return 1.5; case BlockType.Cylinder: return 0.5; case BlockType.Sphere: return 0.5; case BlockType.Beam: return 0.25; case BlockType.CMUWall: return 1.5; default: return 0; } } private void UpdateSmartIndicators(MainViewModel vm) { if (!vm.ShowSmartPlacementHints) { ClearSmartIndicators(vm); return; } bool hasIndicators = vm.Objects.Any(o => o.Type == BlockType.UIIndicator); if (!hasIndicators) { var gridLines = vm.Objects.Where(o => o.Type == BlockType.GridLine).ToList(); var walls = vm.Objects.Where(o => o.Type == BlockType.CMUWall).ToList(); foreach (var line in gridLines) { bool occupied = walls.Any(w => (w.Position - line.Position).Length < 0.1); if (!occupied) { vm.Objects.Add(new SceneObject { Type = BlockType.UIIndicator, Position = new System.Windows.Media.Media3D.Point3D(line.Position.X, line.Position.Y + 2, line.Position.Z), Rotation = new System.Windows.Media.Media3D.Vector3D(0,0,0), Scale = new System.Windows.Media.Media3D.Vector3D(1,1,1) }); } } } } private void ClearSmartIndicators(MainViewModel vm) { var indicators = vm.Objects.Where(o => o.Type == BlockType.UIIndicator).ToList(); foreach (var ind in indicators) { vm.Objects.Remove(ind); } } } }