private void grdViewPort_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { try { if (_isDraggingSelectionBox) { #region Selection Box // Release the mouse capture and stop tracking it. _isDraggingSelectionBox = false; grdViewPort.ReleaseMouseCapture(); // Hide the drag selection box. selectionBox.Visibility = Visibility.Collapsed; if (Math1D.IsNearZero(selectionBox.Width) || Math1D.IsNearZero(selectionBox.Height)) { // This is a miss, because the only way to start a selction box is to not click on anything return; } Point mouseUpPos = e.GetPosition(grdViewPort); // See if the part's centers are inside the rectangular solid. This way they are required to drag the box at least half way thru the part, but minor // touching will be ignored // Cast 4 rays Point topLeft = new Point(Canvas.GetLeft(selectionBox), Canvas.GetTop(selectionBox)); //Point bottomRight = new Point(Canvas.GetRight(selectionBox), Canvas.GetBottom(selectionBox)); // this is just returning NANs for bottom and right Point bottomRight = new Point(topLeft.X + selectionBox.Width, topLeft.Y + selectionBox.Height); var rayTopLeft = UtilityWPF.RayFromViewportPoint(_camera, _viewport, topLeft); var rayTopRight = UtilityWPF.RayFromViewportPoint(_camera, _viewport, new Point(bottomRight.X, topLeft.Y)); var rayBottomLeft = UtilityWPF.RayFromViewportPoint(_camera, _viewport, new Point(topLeft.X, bottomRight.Y)); var rayBottomRight = UtilityWPF.RayFromViewportPoint(_camera, _viewport, bottomRight); List<ITriangle> planes = new List<ITriangle>(); // visualizing this in sketchup is a life saver planes.Add(new Triangle(rayTopLeft.Origin, rayTopRight.Origin, rayTopLeft.Origin + rayTopLeft.Direction)); // top planes.Add(new Triangle(rayTopRight.Origin, rayBottomRight.Origin, rayTopRight.Origin + rayTopRight.Direction)); // right planes.Add(new Triangle(rayBottomRight.Origin, rayBottomLeft.Origin, rayBottomRight.Origin + rayBottomRight.Direction)); // bottom planes.Add(new Triangle(rayBottomLeft.Origin, rayTopLeft.Origin, rayBottomLeft.Origin + rayBottomLeft.Direction)); // left planes.Add(new Triangle(rayTopLeft.Origin, rayBottomRight.Origin, rayTopRight.Origin)); // selection box // Figure out which layers to look at IEnumerable<DesignPart> candidates = null; if (_isAllLayers) { candidates = _parts.SelectMany(o => o); } else { candidates = _parts[_currentLayerIndex]; } // Find all the parts inside this rectangular cone List<DesignPart> hitParts = candidates.Where(o => Math3D.IsInside_Planes(planes, o.Part3D.Position)).ToList(); if (_isCtrlDown && _selectedParts != null) { #region Ctrl+Select if (hitParts.Count > 0) { // Any of the hit parts that are currently in the selection should be removed. Any that aren't should be added List<DesignPart> origSelectedParts = _selectedParts.GetParts().ToList(); foreach (DesignPart hitPart in hitParts) { if (origSelectedParts.Contains(hitPart)) { _selectedParts.Remove(hitPart); } else { _selectedParts.Add(hitPart); } } if (_selectedParts.Count == 0) { ClearSelectedParts(); } } #endregion } else { #region Standard Select ClearSelectedParts(); // doesn't matter if there was a selection or not. A new one is needed if (hitParts.Count > 0) { // Create a selection, and put the hit parts in it _selectedParts = new SelectedParts(_viewport, _camera, _options); _selectedParts.AddRange(hitParts); } #endregion } // Update guidelines if (_selectedParts != null && chkShowGuideLines.IsChecked.Value) { ShowGuideLines(chkShowGuideLinesAllLayers.IsChecked.Value); } #endregion } else if (_isDraggingParts) { #region Finish moving selected parts _isDraggingParts = false; if (_selectedParts != null && _selectedParts.IsDraggingModifier) { _selectedParts.StopDraggingModifier(); } if (_selectedParts != null && _isSelectionDragDirty) { // They moved the selection, so store it in the undo list // Group the parts by layer SortedList<int, List<DesignPart>> selectedPartsByLayer = GetPartsByLayer(_selectedParts.GetParts().ToList()); // Build the undo items List<UndoRedoTransformChange> undoItems = new List<UndoRedoTransformChange>(); foreach (int layerIndex in selectedPartsByLayer.Keys) { undoItems.AddRange(selectedPartsByLayer[layerIndex].Select(o => new UndoRedoTransformChange(o.Part3D.Token, layerIndex) { Orientation = o.Part3D.Orientation, Position = o.Part3D.Position, Scale = o.Part3D.Scale })); } AddNewUndoRedoItem(undoItems.ToArray()); } #endregion } } catch (Exception ex) { MessageBox.Show(ex.ToString(), _msgboxCaption, MessageBoxButton.OK, MessageBoxImage.Error); } }
private void grdViewPort_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { try { _isDraggingParts = false; _isDraggingSelectionBox = false; // Fire a ray at the mouse point Point clickPoint = e.GetPosition(grdViewPort); RayHitTestParameters clickRay; List<MyHitTestResult> hits = UtilityWPF.CastRay(out clickRay, clickPoint, grdViewPort, _camera, _viewport, true, null); // See if they clicked on an existing part DesignPart clickedItem = null; foreach (MyHitTestResult hit in hits.Where(o => o.ModelHit != null)) // skipping the dragshape hit { #region Detect model hit if (_selectedParts != null && !_selectedParts.IsLocked) { if (_selectedParts.IsModifierHit(hit.ModelHit.VisualHit)) { // This is a modifier of the selected item (scale arrow or rotate ring) _selectedParts.StartDraggingModifier(hit.ModelHit.VisualHit, clickPoint); // if alt is pressed, I don't want to copy this, only when they drag the part around _isDraggingParts = true; return; } } IEnumerable<DesignPart> candidates = null; if (_isAllLayers) { candidates = _parts.SelectMany(o => o); } else { candidates = _parts[_currentLayerIndex]; } var matches = candidates.Where(o => o.Model == hit.ModelHit.VisualHit); if (matches.Count() == 1) { clickedItem = matches.First(); break; } #endregion } #region Update selected item // Update the currently selected item if (clickedItem != null && _selectedParts != null && _selectedParts.GetParts().Any(o => o == clickedItem)) { if (_isCtrlDown) { #region Deselect from selected parts // Ctrl clicking a selected part will deselect it _selectedParts.Remove(clickedItem); if (_selectedParts.Count == 0) { ClearSelectedParts(); } #endregion } else { #region Update click point // They clicked on the same part, just update the points _dragMouseDownClickRay = clickRay; _dragMouseDownCenterRay = new RayHitTestParameters(_selectedParts.Position, clickRay.Direction); //TODO: the ray through the center of the part really isn't parallel to the click ray (since the perspective camera sees in a cone) #endregion } } else if (clickedItem != null && _selectedParts != null && _isCtrlDown) { #region Add to current selection _selectedParts.Add(clickedItem); // Remember the click location in case they start dragging _dragMouseDownClickRay = clickRay; _dragMouseDownCenterRay = new RayHitTestParameters(_selectedParts.Position, clickRay.Direction); //TODO: the ray through the center of the part really isn't parallel to the click ray (since the perspective camera sees in a cone) #endregion } else if (clickedItem == null && _isCtrlDown) { // They missed any parts, but are making a ctrl+selectionbox. Do nothing here and let mouseup take care of things } else { #region Changing selection, or unselecting everything ClearSelectedParts(); if (clickedItem != null) { // Select this part _selectedParts = new SelectedParts(_viewport, _camera, _options); _selectedParts.Add(clickedItem); // Remember where they clicked _dragMouseDownClickRay = clickRay; _dragMouseDownCenterRay = new RayHitTestParameters(_selectedParts.Position, clickRay.Direction); //TODO: the ray through the center of the part really isn't parallel to the click ray (since the perspective camera sees in a cone) if (chkShowGuideLines.IsChecked.Value) { ShowGuideLines(chkShowGuideLinesAllLayers.IsChecked.Value); } } #endregion } #endregion if (_isAltDown && _selectedParts != null) { #region Clone part List<UndoRedoAddRemove> undoItems = new List<UndoRedoAddRemove>(); // Make a copies of the selected parts int partIndex = -1; foreach (DesignPart clonedPart in _selectedParts.CloneParts()) { partIndex++; _viewport.Children.Add(clonedPart.Model); if (clonedPart.GuideLines != null) { _viewport.Children.Add(clonedPart.GuideLines); } int layerIndex = _currentLayerIndex; if (_isAllLayers) { List<DesignPart> origParts = _selectedParts.GetParts().ToList(); for (int cntr = 0; cntr < _parts.Count; cntr++) { if (_parts[cntr].Contains(origParts[partIndex])) { layerIndex = cntr; break; } } } _parts[layerIndex].Add(clonedPart); // Build undo item undoItems.Add(new UndoRedoAddRemove(true, clonedPart, layerIndex)); } // Store the undo items if (undoItems.Count > 0) // parts that need to be unique can't be cloned { AddNewUndoRedoItem(undoItems.ToArray()); } else { ShowErrorMsg("Can't copy this part"); } #endregion } if ((_selectedParts == null) || (clickedItem == null && _isCtrlDown)) { #region Start selection rectangle if (!_isDraggingSelectionBox) { _isDraggingSelectionBox = true; _selectionBoxMouseDownPos = e.GetPosition(grdViewPort); grdViewPort.CaptureMouse(); // Initial placement of the drag selection box Canvas.SetLeft(selectionBox, _selectionBoxMouseDownPos.X); Canvas.SetTop(selectionBox, _selectionBoxMouseDownPos.Y); selectionBox.Width = 0; selectionBox.Height = 0; // Make the drag selection box visible. selectionBox.Visibility = Visibility.Visible; } #endregion } else if (clickedItem != null && _isCtrlDown) { // They just deselected a part. Don't drag, don't make a selection box } else { _isDraggingParts = true; _mouseDownDragPos = _selectedParts.Position; _mouseDownDragOrientation = _selectedParts.Orientation.ToUnit(); _isSelectionDragDirty = false; } // Make sure the drag shape is current ChangeDragHitShape(); } catch (Exception ex) { MessageBox.Show(ex.ToString(), _msgboxCaption, MessageBoxButton.OK, MessageBoxImage.Error); } }
private void SelectAllParts() { ClearSelectedParts(); // doesn't matter if there was a selection or not. A new one is needed if (!_isAllLayers && (_parts[_currentLayerIndex].Count == 0 || !((LayerRow)pnlLayers.Children[_currentLayerIndex + 1]).IsLayerVisible)) { // There are no parts in this layer return; } // Create a selection, and put the hit parts in it _selectedParts = new SelectedParts(_viewport, _camera, _options); if (_isAllLayers) { _selectedParts.AddRange(_parts.SelectMany(o => o)); } else { _selectedParts.AddRange(_parts[_currentLayerIndex]); } }
private void Paste() { if (_clipboard == null || _clipboard.Length == 0) { return; } ClearSelectedParts(); List<DesignPart> pastedParts = new List<DesignPart>(); List<UndoRedoAddRemove> undoItems = new List<UndoRedoAddRemove>(); // Paste the parts foreach (DesignPart clipPart in _clipboard) { // Clone it DesignPart part = clipPart.Clone(); // Add it _viewport.Children.Add(part.Model); _parts[_currentLayerIndex].Add(part); // Remember this part undoItems.Add(new UndoRedoAddRemove(true, part, _currentLayerIndex)); pastedParts.Add(part); } // Store the undo items AddNewUndoRedoItem(undoItems.ToArray()); // Select the newly pasted parts _selectedParts = new SelectedParts(_viewport, _camera, _options); _selectedParts.AddRange(pastedParts); if (chkShowGuideLines.IsChecked.Value) { ShowGuideLines(chkShowGuideLinesAllLayers.IsChecked.Value); } }
private void ClearSelectedParts() { HideGuideLines(); if (_selectedParts != null) { // Wipe out any selection visuals _selectedParts.Clear(); } _selectedParts = null; }