public DuplicateBrick(LayerBrick layer, List <Layer.LayerItem> bricksToDuplicate, bool needToAddOffset) : base(bricksToDuplicate, needToAddOffset, Budget.Budget.Instance.ShouldUseBudgetLimitation) { // init the layer mBrickLayer = layer; // elagate the list according to the budget limit mWereItemsTrimmed = trimItemListWithBudgetLimitation(); // get bricks for the notification from the trimmed list mBricksForNotification = Layer.sFilterListToGetOnlyBricksInLibrary(mItems); // remove the group that were added to the item list for brick notification purpose // they are added at the end, so find the first one and erase the end if (Budget.Budget.Instance.ShouldUseBudgetLimitation) { for (int i = 0; i < mItems.Count; ++i) { if (mItems[i].IsAGroup) { mItems.RemoveRange(i, mItems.Count - i); break; } } } // try to get a part number (which can be the name of a group) Layer.LayerItem topItem = Layer.sGetTopItemFromList(mItems); if (topItem != null) { mPartNumber = topItem.PartNumber; } }
public DuplicateBrick(LayerBrick layer, List<Layer.LayerItem> bricksToDuplicate, bool needToAddOffset) : base(bricksToDuplicate, needToAddOffset, Budget.Budget.Instance.ShouldUseBudgetLimitation) { // init the layer mBrickLayer = layer; // elagate the list according to the budget limit mWereItemsTrimmed = trimItemListWithBudgetLimitation(); // get bricks for the notification from the trimmed list mBricksForNotification = Layer.sFilterListToGetOnlyBricksInLibrary(mItems); // remove the group that were added to the item list for brick notification purpose // they are added at the end, so find the first one and erase the end if (Budget.Budget.Instance.ShouldUseBudgetLimitation) for (int i = 0; i < mItems.Count; ++i) if (mItems[i].IsAGroup) { mItems.RemoveRange(i, mItems.Count - i); break; } // try to get a part number (which can be the name of a group) Layer.LayerItem topItem = Layer.sGetTopItemFromList(mItems); if (topItem != null) mPartNumber = topItem.PartNumber; }
/// <summary> /// this method should be called when a brick is added /// </summary> public void addBrickNotification(LayerBrick layer, Layer.LayerItem brickOrGroup, bool isDueToRegroup) { // do nothing if the window is not visible // because we rebuild everything when it becomes visible if (!this.Visible) return; // get the group entry associated with this layer GroupEntry currentGroupEntry = getGroupEntryFromLayer(layer, true); // add the specified brick addBrick(brickOrGroup, currentGroupEntry); // if the specified brick is group, add also the sub items in the list if (brickOrGroup.IsAGroup) foreach (Layer.LayerItem item in (brickOrGroup as Layer.Group).Items) if (item.PartNumber != string.Empty) // item can be a brick or another named group, but we should not add unnamed group { if (isDueToRegroup) { if (!BrickLibrary.Instance.isListedInLibrary(item.PartNumber)) this.removeBrickNotification(layer, item, false); // don't use true otherwise it's an infinite loop } else { if (BrickLibrary.Instance.isListedInLibrary(item.PartNumber)) this.addBrickNotification(layer, item, false); // anyway isDueToRegroup is false } } }
/// <summary> /// Get the percentage of usage for the specified layer, according to the current budget. /// This method will iterate on all the bricks present on the specified layer and will /// sum all the budget of those bricks. Then it will compute a percentage between the /// total count of the budgeted bricks on this layer, and the total budget count computed. /// </summary> /// <param name="layer">The layer in which you want to know the brick usage</param> /// <param name="totalBudgetForTheLayer">this out parameter will contains the total budget count for the parts used on the layer</param> /// <returns>the brick usage percentage on the specified layer</returns> public float getUsagePercentageForLayer(LayerBrick layer, out int totalBudgetForTheLayer) { float result = 0; totalBudgetForTheLayer = 0; // try to get the specified layer and iterate on all its values Dictionary <string, int> layeredCount = null; if (mCountPerLayer.TryGetValue(layer, out layeredCount)) { int totalCount = 0; // itearate on all the pair on the specified layer foreach (KeyValuePair <string, int> brickCount in layeredCount) { // check if the current brick has a budget, otherwise ignore it int budget = 0; if (mBudget.TryGetValue(brickCount.Key, out budget)) { // increase the count and budget totalCount += brickCount.Value; totalBudgetForTheLayer += budget; } } // compute the result (if budget is not null to avoid division by zero) if (totalBudgetForTheLayer > 0) { result = (float)(totalCount * 100) / (float)totalBudgetForTheLayer; } } return(result); }
private void buttonOk_Click(object sender, EventArgs e) { // create a copy of the edited layer to hold the old data LayerBrick oldLayerData = new LayerBrick(); oldLayerData.CopyOptionsFrom(mEditedLayer); // create a new layer to store the new data LayerBrick newLayerData = new LayerBrick(); // name and visibility newLayerData.Name = this.nameTextBox.Text; newLayerData.Visible = this.isVisibleCheckBox.Checked; //transparency newLayerData.Transparency = (int)(this.alphaNumericUpDown.Value); // hull newLayerData.DisplayHulls = this.displayHullCheckBox.Checked; newLayerData.PenToDrawHull = new Pen(mHullColor, (int)hullThicknessNumericUpDown.Value); // brick elevation newLayerData.DisplayBrickElevation = this.displayBrickElevationCheckBox.Checked; // do a change option action ActionManager.Instance.doAction(new ChangeLayerOption(mEditedLayer, oldLayerData, newLayerData)); }
private string mPartNumber = string.Empty; //if the list contains only one brick or one group, this is the name of this specific brick or group public DeleteBrick(LayerBrick layer, List <Layer.LayerItem> bricksToDelete) { mBrickLayer = layer; mBrickIndex = new List <int>(bricksToDelete.Count); mBricksForNotification = Layer.sFilterListToGetOnlyBricksInLibrary(bricksToDelete); // copy the list, because the pointer may change (specially if it is the selection) mBricks = new List <Layer.LayerItem>(bricksToDelete.Count); foreach (Layer.LayerItem obj in bricksToDelete) { mBricks.Add(obj); } // try to get a part number (which can be the name of a group) Layer.LayerItem topItem = Layer.sGetTopItemFromList(mBricks); if (topItem != null) { if (topItem.IsAGroup) { mPartNumber = (topItem as Layer.Group).PartNumber; } else { mPartNumber = (topItem as LayerBrick.Brick).PartNumber; } } }
public AddBrick(LayerBrick layer, Layer.LayerItem brickOrGroup) { mBrickLayer = layer; mBrickOrGroup = brickOrGroup; // after setting the brick or group, call the init brick list function initBrickList(); }
public void addAllBrickConnections(LayerBrick.Brick brick) { // add its connection points to the free list if (brick.HasConnectionPoint) foreach (LayerBrick.Brick.ConnectionPoint connection in brick.ConnectionPoints) mFreeConnections[connection.Type].Add(connection); }
private int mNextPreferedActiveConnectionIndex = 0; // the prefered active connection index according to the brick library #endregion Fields #region Constructors public AddConnectBrick(LayerBrick layer, string partNumber, int wantedConnexion) { mBrickLayer = layer; mBrick = new LayerBrick.Brick(partNumber); LayerBrick.Brick selectedBrick = layer.getConnectableBrick(); if (selectedBrick != null) { // check if the selected brick has connection point if (selectedBrick.HasConnectionPoint && mBrick.HasConnectionPoint) { // choose the best active connection point for the brick setBestConnectionPointIndex(selectedBrick, mBrick, wantedConnexion); // after setting the active connection point index from which this brick will be attached, // get the prefered index from the library mNextPreferedActiveConnectionIndex = BrickLibrary.Instance.getConnectionNextPreferedIndex(partNumber, mBrick.ActiveConnectionPointIndex); // then rotate the brick to connect mBrick.Orientation = sGetOrientationOfConnectedBrick(selectedBrick, mBrick); // the place the brick to add at the correct position mBrick.ActiveConnectionPosition = selectedBrick.ActiveConnectionPosition; } else { PointF position = selectedBrick.Position; position.X += selectedBrick.DisplayArea.Width; mBrick.Position = position; } // set the index of the brick in the list just after the selected brick mBrickIndex = layer.BrickList.IndexOf(selectedBrick) + 1; } }
public AttachRulerToBrick(LayerRuler.RulerItem rulerItem, LayerBrick.Brick brick) { // compute the attach offset in local coordinate PointF attachOffset = RulerAttachementSet.Anchor.sComputeLocalOffsetFromLayerItem(brick, rulerItem.CurrentControlPoint); // create a new Anchor mAnchor = new RulerAttachementSet.Anchor(rulerItem, rulerItem.CurrentControlPointIndex, attachOffset); mBrick = brick; }
private void SelectAllButton_Click(object sender, EventArgs e) { // get the search part string searchingPartNumber = this.FindComboBox.SelectedItem as string; // the new list of object to select List <Layer.LayerItem> objectToSelect = new List <Layer.LayerItem>(); // get the current selected layer because we will need it (normally it is never null) Layer selectedLayer = Map.Instance.SelectedLayer; if (selectedLayer != null) { // check if the selection must be performed in the current selection // or in a new layer if (this.inCurrentSelectionRadioButton.Checked) { // sub select in current selection, iterate on the selection int nbSelectedItems = selectedLayer.SelectedObjects.Count; for (int i = 0; i < nbSelectedItems; ++i) { Layer.LayerItem currentItem = selectedLayer.SelectedObjects[i]; string currentPartNumber = (currentItem as LayerBrick.Brick).PartNumber; if (currentPartNumber.Equals(searchingPartNumber)) { objectToSelect.Add(currentItem); } } } else if (this.LayerCheckedListBox.CheckedItems.Count == 1) { // find in which layer the selection should be done LayerBrick layerToSelect = mBrickOnlyLayerList[this.LayerCheckedListBox.CheckedIndices[0]]; // First we need to select the target layer if not already selected if (selectedLayer != layerToSelect) { Actions.ActionManager.Instance.doAction(new Actions.Layers.SelectLayer(layerToSelect)); // important to update the new selected layer for the rest of the code selectedLayer = layerToSelect; } // then iterate on all the bricks of the selected layer to find the one we search foreach (LayerBrick.Brick brick in layerToSelect.BrickList) { if (brick.PartNumber.Equals(searchingPartNumber)) { objectToSelect.Add(brick); } } } } // select the new objects selectedLayer.clearSelection(); selectedLayer.addObjectInSelection(objectToSelect); // close the window this.Close(); }
private void replaceOneItem(LayerBrick layer, Layer.LayerItem itemToRemove, Layer.LayerItem itemToAdd) { // memorise the brick index order and the group of the old brick int oldItemIndex = -1; Layer.Group oldItemGroup = itemToRemove.Group; // first remove the item from its group, in case it belongs to a group // (so that later if someone ask all item of this group, it won't get this limbo item) if (itemToRemove.Group != null) { itemToRemove.Group.removeItem(itemToRemove); } // check if the item to remove is a group or a simple brick if (itemToRemove.IsAGroup) { List <Layer.LayerItem> bricksToRemove = (itemToRemove as Layer.Group).getAllLeafItems(); foreach (Layer.LayerItem item in bricksToRemove) { oldItemIndex = layer.removeBrick(item as LayerBrick.Brick); } // we alsways take the last index to be sure we don't keep an index bigger than the brick list // after removing all the parts of the group } else { oldItemIndex = layer.removeBrick(itemToRemove as LayerBrick.Brick); } // check if the item to add is a group or a simple brick if (itemToAdd.IsAGroup) { List <Layer.LayerItem> bricksToAdd = (itemToAdd as Layer.Group).getAllLeafItems(); // since we will add all the brick at the same index, iterating in the normal order // the insertion order will be reversed. So we reverse the list to make the insertion in correct order bricksToAdd.Reverse(); foreach (Layer.LayerItem item in bricksToAdd) { layer.addBrick(item as LayerBrick.Brick, oldItemIndex); } } else { layer.addBrick(itemToAdd as LayerBrick.Brick, oldItemIndex); } // then once the item has been added to the layer, add it also to the group if the old item had a group if (oldItemGroup != null) { oldItemGroup.addItem(itemToAdd); } // notify the part list view (after actually adding and deleting the bricks because the total map size need to be recomputed) MainForm.Instance.NotifyPartListForBrickRemoved(layer, itemToRemove, false); MainForm.Instance.NotifyPartListForBrickAdded(layer, itemToAdd, false); }
/// <summary> /// The constructor should be called before starting to update the flex chain, /// because the action save the initial state of the bricks in the constructor /// This constructor Create a flex chain from a set of brick given a starting brick. From the best connection point /// of this starting brick go through all the linked connection points while the brick only have /// two connections. If the brick has only one or more than 2 connection (like a joint or crossing) /// we stop the chain. /// </summary> /// <param name="layer">The layer on which the flex move is performed</param> /// <param name="trackList">A set of track hopefully connected together, and hopefully containing flex track</param> /// <param name="grabbedTrack">The part which will try to reach the target. It should be part of the list.</param> /// <param name="mouseCoordInStud">the coordinate of the mouse in stud coord</param> public FlexMove(LayerBrick layer, List <Layer.LayerItem> trackList, LayerBrick.Brick grabbedTrack, PointF mouseCoordInStud) { // first we check if we can create a valid flex chain mIsValid = false; // check that the grabbed part is a part has 1 or 2 connection points (no more no less) if (!grabbedTrack.HasConnectionPoint || grabbedTrack.ConnectionPoints.Count > 2) { return; } // if the grabbed part is not in the list, it failed if (!trackList.Contains(grabbedTrack)) { return; } // declare a variable for the starting connection, we will pass it to the flex creation // this variable can stay null, in that case the middle of the grabbed part will be used instead LayerBrick.Brick.ConnectionPoint startConnection = null; // declare a variable to know from which connection to start the flex chain if (grabbedTrack.ConnectionPoints.Count == 1) { // if there's only one connection, if must be a flexible one, and // the starting connection will be the brick itself // and the only connection will be the second one from which starting the chain if (BrickLibrary.Instance.getConnexionHingeAngle(grabbedTrack.ConnectionPoints[0].Type) == 0.0f) { return; } } else { // try to find the starting connection point, if the result is null, the flex chain cannot be created startConnection = findStartingConnectionPoint(trackList, grabbedTrack, mouseCoordInStud); if (startConnection == null) { return; } } // if we pass all the tests, the flex move is valid mIsValid = true; // init other data member mBrickLayer = layer; //create the edition data ceateFlexChain(trackList, grabbedTrack, startConnection); // and save the action data recordState(ref mInitState); // also save the current selection, because we will only select the flex brick for visual feedback // Do not save directly the list object because we will modified the selection mSelectedBricksBeforeFlexMove = new List <Layer.LayerItem>(layer.SelectedObjects); // now clear the slection and select only the bricks in the flex chain layer.unsafeSetSelection(mBricksInTheFlexChain); }
private void replace(bool newByOld) { // iterate on all the layers for (int i = 0; i < mBrickLayerList.Count; ++i) { // get the layer and the list of brick pair to replace LayerBrick currentLayer = mBrickLayerList[i]; List <BrickPair> currentPairList = mBrickPairList[i]; // clear the selection (we will select the replaced brick for updating the connectivity) currentLayer.clearSelection(); if (currentPairList.Count > 0) { // iterate on all the brick pair foreach (BrickPair brickPair in currentPairList) { // get the old and new brick Layer.LayerItem oldOne = brickPair.mOldBrick; Layer.LayerItem newOne = brickPair.mNewBrick; // reverse them if needed if (newByOld) { oldOne = brickPair.mNewBrick; newOne = brickPair.mOldBrick; } // replace the old brick with the new one in the current layer replaceOneItem(currentLayer, oldOne, newOne); // add the brick in the selection for updating connectivity later currentLayer.addObjectInSelection(newOne); } // update the connectivity of the whole layer after replacement currentLayer.updateFullBrickConnectivityForSelectedBricksOnly(); // clear the selection again (it was only use for fast connectivity update) currentLayer.clearSelection(); } // If the current layer is the one which has the selection // reselect all the new brick if (currentLayer == mLayerWhereToSelectTheReplacedBricks) { foreach (BrickPair brickPair in mReplacedBricksToSelect) { if (newByOld) { currentLayer.addObjectInSelection(brickPair.mOldBrick); } else { currentLayer.addObjectInSelection(brickPair.mNewBrick); } } } } }
private string mPartNumber = string.Empty; //if the list contains only one brick or one group, this is the name of this specific brick or group public MoveBrick(LayerBrick layer, List <Layer.LayerItem> bricks, PointF move) : base(layer, bricks, move) { // try to get a part number (which can be the name of a group) Layer.LayerItem topItem = Layer.sGetTopItemFromList(mItems); if (topItem != null) { mPartNumber = topItem.PartNumber; // part number is virtual, works both for part and group } }
public AddBrick(LayerBrick layer, string partNumber) { mBrickLayer = layer; if (BrickLibrary.Instance.isAGroup(partNumber)) mBrickOrGroup = new Layer.Group(partNumber); else mBrickOrGroup = new LayerBrick.Brick(partNumber); // after setting the brick or group, call the init brick list function initBrickList(); }
public static void check(LayerBrick.Brick startingBrick) { // check that the specified brick is an electric brick, else do nothing if (startingBrick.ElectricCircuitIndexList != null) { // increment the time stamp incrementTimeStamp(); // call the main method checkFromOneBrick(startingBrick); } }
public static void check(LayerBrick brickLayer) { // increment the time stamp incrementTimeStamp(); // check for every brick if not already at the time stamp foreach (LayerBrick.Brick brick in brickLayer.BrickList) if (brick.ElectricCircuitIndexList != null) if (Math.Abs(brick.ConnectionPoints[0].Polarity) != sTimeStamp) checkFromOneBrick(brick); }
/// <summary> /// Get the total number of bricks present in the specified layer of the current map /// </summary> /// <param name="layer">The layer in which you want to know the count</param> /// <param name="onlyBudgetedParts">if true only the budgeted parts will be counted, otherwise all the parts on the layer</param> /// <returns>the number of bricks in the specified layer of the map which could be 0</returns> public int getTotalCountForLayer(LayerBrick layer, bool onlyBudgetedParts) { int result = 0; // try to get the specified layer and iterate on all its values Dictionary <string, int> layeredCount = null; if (mCountPerLayer.TryGetValue(layer, out layeredCount)) { result = getCountInDictionary(layeredCount, onlyBudgetedParts); } return(result); }
/// <summary> /// Add a new single part which has the specified partNumber on the specifier layer, and connected it to /// the specified selectedItem (part or group) using the specified wanted connection for that new part. /// </summary> /// <param name="layer">The layer on which to add the part, and in which the selectedItem is selected</param> /// <param name="selectedItem">The single selected item (this can be a single part or a single group). This parameter cannot be null.</param> /// <param name="partNumber">The number of the part to add</param> /// <param name="wantedConnexion">The connection index of the part to add that should be used to connect to the selected item, or -1 if you don't care.</param> public AddConnectBrick(LayerBrick layer, Layer.LayerItem selectedItem, string partNumber, int wantedConnexion) { // the selected item should not be null System.Diagnostics.Debug.Assert(selectedItem != null); mBrickLayer = layer; mBrick = new LayerBrick.Brick(partNumber); LayerBrick.Brick selectedBrick = layer.getConnectableBrick(); bool hasAGoodConnectionBeenFound = false; // check if the selected brick and the brick to add have connection points, and if we can find a good connection match // The selected brick can be null if there's no connection in the single group connected in the layer if ((selectedBrick != null) && selectedBrick.HasConnectionPoint && mBrick.HasConnectionPoint) { // choose the best active connection point for the brick hasAGoodConnectionBeenFound = setBestConnectionPointIndex(selectedBrick, mBrick, wantedConnexion); } // check if we found a good connection, continue to set the position of the brick to add relative to the connection if (hasAGoodConnectionBeenFound) { // then rotate the brick to connect mBrick.Orientation = sGetOrientationOfConnectedBrick(selectedBrick, mBrick); // the place the brick to add at the correct position mBrick.ActiveConnectionPosition = selectedBrick.ActiveConnectionPosition; } else { // and just compute the position to the right of the selected item PointF position = selectedItem.Position; position.X += selectedItem.DisplayArea.Width; mBrick.Position = position; // the reassing the selected brick with the first brick of the group if the selected item is a group // so that the brick index can correctly be set if (selectedItem.IsAGroup) { selectedBrick = (selectedItem as Layer.Group).getAllLeafItems()[0] as LayerBrick.Brick; } else { selectedBrick = selectedItem as LayerBrick.Brick; } } // set the index of the brick in the list just after the selected brick if (selectedBrick != null) { mBrickIndex = layer.BrickList.IndexOf(selectedBrick) + 1; } }
private List <int> mBrickIndex = null; // this list of index is for the redo, to add each text at the same place public AddBrick(LayerBrick layer, string partNumber) { mBrickLayer = layer; if (BrickLibrary.Instance.isAGroup(partNumber)) { mBrickOrGroup = new Layer.Group(partNumber); } else { mBrickOrGroup = new LayerBrick.Brick(partNumber); } // after setting the brick or group, call the init brick list function initBrickList(); }
public override void undo() { LayerBrick brickLayer = mLayer as LayerBrick; // reselect the items of the action, cause after we will update the connectivity of the selection // and do it before calling the base class cause the base class will update the selection rectangle brickLayer.selectOnlyThisObject(mItems); // call the base class base.undo(); // update the brick connectivity brickLayer.updateBrickConnectivityOfSelection(false); // notify the main form for the brick move MainForm.Instance.NotifyForPartMoved(); }
private int mNextPreferedActiveConnectionIndex = 0; // the prefered active connection index according to the brick library #endregion Fields #region Constructors public AddConnectGroup(LayerBrick layer, string partNumber, int wantedConnexion) { // save the layer and construct the group mBrickLayer = layer; mGroup = new Layer.Group(partNumber); LayerBrick.Brick selectedBrick = layer.getConnectableBrick(); // get the flat list of bricks from the hierarchical group mBricksInTheGroup = mGroup.getAllLeafItems(); // check if we can attach the group to the unique selected object if (selectedBrick != null) { // find the brick of the group that will be connected to the selected brick LayerBrick.Brick brickToConnect = null; if (selectedBrick.HasConnectionPoint) brickToConnect = findBrickToConnectAdnSetBestConnectionPointIndex(selectedBrick, ref wantedConnexion); // check if the selected brick has connection point if (brickToConnect != null && brickToConnect.HasConnectionPoint) { // after setting the active connection point index from which this brick will be attached, // get the prefered index from the library mNextPreferedActiveConnectionIndex = BrickLibrary.Instance.getConnectionNextPreferedIndex(partNumber, wantedConnexion); // Compute the orientation of the bricks float newOrientation = AddConnectBrick.sGetOrientationOfConnectedBrick(selectedBrick, brickToConnect); newOrientation -= brickToConnect.Orientation; // Rotate all the bricks of the group first before translating RotateBrickOnPivotBrick rotateBricksAction = new RotateBrickOnPivotBrick(layer, mBricksInTheGroup, newOrientation, brickToConnect); rotateBricksAction.MustUpdateBrickConnectivity = false; rotateBricksAction.redo(); // compute the translation to add to all the bricks PointF translation = new PointF(selectedBrick.ActiveConnectionPosition.X - brickToConnect.ActiveConnectionPosition.X, selectedBrick.ActiveConnectionPosition.Y - brickToConnect.ActiveConnectionPosition.Y); mGroup.translate(translation); } else { PointF position = selectedBrick.Position; position.X += selectedBrick.DisplayArea.Width; mGroup.Position = position; } // set the index of the brick in the list just after the selected brick mInsertIndex = layer.BrickList.IndexOf(selectedBrick) + 1; } }
/// <summary> /// The constructor should be called before starting to update the flex chain, /// because the action save the initial state of the bricks in the constructor /// This constructor Create a flex chain from a set of brick given a starting brick. From the best connection point /// of this starting brick go through all the linked connection points while the brick only have /// two connections. If the brick has only one or more than 2 connection (like a joint or crossing) /// we stop the chain. /// </summary> /// <param name="layer">The layer on which the flex move is performed</param> /// <param name="trackList">A set of track hopefully connected together, and hopefully containing flex track</param> /// <param name="grabbedTrack">The part which will try to reach the target. It should be part of the list.</param> /// <param name="mouseCoordInStud">the coordinate of the mouse in stud coord</param> public FlexMove(LayerBrick layer, List<Layer.LayerItem> trackList, LayerBrick.Brick grabbedTrack, PointF mouseCoordInStud) { // first we check if we can create a valid flex chain mIsValid = false; // check that the grabbed part is a part has 1 or 2 connection points (no more no less) if (!grabbedTrack.HasConnectionPoint || grabbedTrack.ConnectionPoints.Count > 2) return; // if the grabbed part is not in the list, it failed if (!trackList.Contains(grabbedTrack)) return; // declare a variable for the starting connection, we will pass it to the flex creation // this variable can stay null, in that case the middle of the grabbed part will be used instead LayerBrick.Brick.ConnectionPoint startConnection = null; // declare a variable to know from which connection to start the flex chain if (grabbedTrack.ConnectionPoints.Count == 1) { // if there's only one connection, if must be a flexible one, and // the starting connection will be the brick itself // and the only connection will be the second one from which starting the chain if (BrickLibrary.Instance.getConnexionHingeAngle(grabbedTrack.ConnectionPoints[0].Type) == 0.0f) return; } else { // try to find the starting connection point, if the result is null, the flex chain cannot be created startConnection = findStartingConnectionPoint(trackList, grabbedTrack, mouseCoordInStud); if (startConnection == null) return; } // if we pass all the tests, the flex move is valid mIsValid = true; // init other data member mBrickLayer = layer; //create the edition data ceateFlexChain(trackList, grabbedTrack, startConnection); // and save the action data recordState(ref mInitState); // also save the current selection, because we will only select the flex brick for visual feedback // Do not save directly the list object because we will modified the selection mSelectedBricksBeforeFlexMove = new List<Layer.LayerItem>(layer.SelectedObjects); // now clear the slection and select only the bricks in the flex chain layer.unsafeSetSelection(mBricksInTheFlexChain); }
public static void check(LayerBrick brickLayer) { // increment the time stamp incrementTimeStamp(); // check for every brick if not already at the time stamp foreach (LayerBrick.Brick brick in brickLayer.BrickList) { if (brick.ElectricCircuitIndexList != null) { if (Math.Abs(brick.ConnectionPoints[0].Polarity) != sTimeStamp) { checkFromOneBrick(brick); } } } }
/// <summary> /// Call this method when you want to notify the budget counter that a new brick has been added /// </summary> /// <param name="layer">The layer on which the brick is added</param> /// <param name="brick">the brick that was added</param> /// <param name="isDueToRegroup">tells if the brick is a group that was regrouped by an undo</param> public void addBrickNotification(LayerBrick layer, Layer.LayerItem brickOrGroup, bool isDueToRegroup) { string partID = brickOrGroup.PartNumber; if (partID != string.Empty) { // get the current count in the count dictionary int currentCount = 0; mCount.TryGetValue(partID, out currentCount); // and update the value in the global dictionnary mCount.Remove(partID); mCount.Add(partID, currentCount + 1); // also update in the layered dictionary Dictionary <string, int> layeredCount = null; if (mCountPerLayer.TryGetValue(layer, out layeredCount)) { int currentCountInLayer = 0; layeredCount.TryGetValue(partID, out currentCountInLayer); layeredCount.Remove(partID); layeredCount.Add(partID, currentCountInLayer + 1); } else { // this is a new layer (this layer didn't exist before), so add the layer and also the count layeredCount = new Dictionary <string, int>(); layeredCount.Add(partID, 1); mCountPerLayer.Add(layer, layeredCount); } } // add also all the named children if the brick is a group // (unless it is a regroup in that case the children are already counted) if (!isDueToRegroup) { Layer.Group group = brickOrGroup as Layer.Group; if (group != null) { foreach (Layer.LayerItem item in group.Items) { addBrickNotification(layer, item, isDueToRegroup); } } } }
/// <summary> /// Call this method when you want to notify the budget counter that a brick has been removed /// </summary> /// <param name="layer">The layer on which the brick is removed</param> /// <param name="brick">the brick that was removed</param> /// <param name="isDueToUngroup">tell if the brick is a group that is ungrouped</param> public void removeBrickNotification(LayerBrick layer, Layer.LayerItem brickOrGroup, bool isDueToUngroup) { string partID = brickOrGroup.PartNumber; if (partID != string.Empty) { // get the current count int currentCount = 0; mCount.TryGetValue(partID, out currentCount); if (currentCount > 0) { // update the value mCount.Remove(partID); mCount.Add(partID, currentCount - 1); } // also update in the layered dictionary Dictionary <string, int> layeredCount = null; if (mCountPerLayer.TryGetValue(layer, out layeredCount)) { int currentCountInLayer = 0; layeredCount.TryGetValue(partID, out currentCountInLayer); if (currentCountInLayer > 0) { layeredCount.Remove(partID); layeredCount.Add(partID, currentCountInLayer - 1); } } // if the layer doesn't exist, we have nothing to remove } // remove also all the named children if the brick is a group // (unless it is a ungroup in that case we leave the children and just remove the one we ungrouped) if (!isDueToUngroup) { Layer.Group group = brickOrGroup as Layer.Group; if (group != null) { foreach (Layer.LayerItem item in group.Items) { removeBrickNotification(layer, item, isDueToUngroup); } } } }
private List <BriCkAndIndex> mBrickIndex = null; // this list of index is for the redo, to add each text at the same place public ChangeBrickElevation(LayerBrick layer, List <LayerBrick.Brick> bricksToEdit, float newElevation) { // save the item list to edit and the other parameters mLayer = layer; mBricksToEdit = bricksToEdit; mNewElevation = newElevation; // and memorise the elevation of all the bricks and also its original index (for the undo) mOldElevationForEachBrick = new List <float>(bricksToEdit.Count); mBrickIndex = new List <BriCkAndIndex>(bricksToEdit.Count); foreach (LayerBrick.Brick brick in bricksToEdit) { mOldElevationForEachBrick.Add(brick.Altitude); mBrickIndex.Add(new BriCkAndIndex() { mBrick = brick, mIndex = mLayer.BrickList.IndexOf(brick) }); } // sort the brick index list mBrickIndex.Sort((x, y) => x.mIndex - y.mIndex); }
private string mPartNumber = string.Empty; //if the list contains only one brick or one group, this is the name of this specific brick or group #endregion Fields #region Constructors public DeleteBrick(LayerBrick layer, List<Layer.LayerItem> bricksToDelete) { mBrickLayer = layer; mBrickIndex = new List<int>(bricksToDelete.Count); mBricksForNotification = Layer.sFilterListToGetOnlyBricksInLibrary(bricksToDelete); // copy the list, because the pointer may change (specially if it is the selection) mBricks = new List<Layer.LayerItem>(bricksToDelete.Count); foreach (Layer.LayerItem obj in bricksToDelete) mBricks.Add(obj); // try to get a part number (which can be the name of a group) Layer.LayerItem topItem = Layer.sGetTopItemFromList(mBricks); if (topItem != null) { if (topItem.IsAGroup) mPartNumber = (topItem as Layer.Group).PartNumber; else mPartNumber = (topItem as LayerBrick.Brick).PartNumber; } }
public LayerBrickOptionForm(LayerBrick layer) { InitializeComponent(); // save the reference on the layer that we are editing mEditedLayer = layer; // update the controls with the data of the gridLayer // name and visibility this.nameTextBox.Text = layer.Name; this.isVisibleCheckBox.Checked = layer.Visible; // transparency this.alphaNumericUpDown.Value = layer.Transparency; this.alphaTrackBar.Value = layer.Transparency; // the display hull settings this.displayHullCheckBox.Checked = layer.DisplayHulls; updateHullColor(layer.PenToDrawHull.Color); hullThicknessNumericUpDown.Value = (int)layer.PenToDrawHull.Width; // call the checkchange to force the enable of the hull color option displayHullCheckBox_CheckedChanged(this, null); // brick elevation this.displayBrickElevationCheckBox.Checked = layer.DisplayBrickElevation; }
/// <summary> /// Recount all the bricks in the current Map. /// </summary> public void recountAllBricks() { // clear the count of all the bricks mCount.Clear(); mCountPerLayer.Clear(); // iterate on all the brick of all the brick layers, foreach (Layer layer in Map.Instance.LayerList) { LayerBrick brickLayer = layer as LayerBrick; if (brickLayer != null) { // add a layered count for this current layer Dictionary <string, int> layeredCount = new Dictionary <string, int>(); mCountPerLayer.Add(brickLayer, layeredCount); // now iterate on all the brick of the current layer foreach (Layer.LayerItem item in brickLayer.LibraryBrickList) { // get the part id string partID = item.PartNumber; // get the current global count int currentCount = 0; mCount.TryGetValue(partID, out currentCount); // update the value mCount.Remove(partID); mCount.Add(partID, currentCount + 1); // also count the brick on the layered count int currentCountInLayer = 0; layeredCount.TryGetValue(partID, out currentCountInLayer); // update the value layeredCount.Remove(partID); layeredCount.Add(partID, currentCountInLayer + 1); } } } }
/// <summary> /// Try to find the best connection index that should be used for the brickToAttach when we attach it /// to the current active connection point of the fixedBrick, and set it. /// </summary> /// <param name="fixedBrick">The brick that doesn't move neither change its connection point</param> /// <param name="brickToAttach">The brick for which computing the best connection point</param> /// <param name="wantedConnexion">The prefered connection index if possible</param> private void setBestConnectionPointIndex(LayerBrick.Brick fixedBrick, LayerBrick.Brick brickToAttach, int wantedConnexion) { // get the type of the active connexion of the selected brick int fixedConnexionType = fixedBrick.ActiveConnectionPoint.Type; // try to give the correct connexion point, either the specified wanted one, or if // we add the same brick do a special case bool isActiveConnectionPointChosen = false; if (wantedConnexion >= 0) { // set the active connexion point with the wanted one brickToAttach.ActiveConnectionPointIndex = wantedConnexion; // check that the wanted connection type is the same as the selected brick isActiveConnectionPointChosen = (brickToAttach.ActiveConnectionPoint.Type == fixedConnexionType) && brickToAttach.ActiveConnectionPoint.IsFree; } else if (fixedBrick.PartNumber == brickToAttach.PartNumber) { // check if the new added brick is the same kind of the selected one, if so, // then we choose the previous connection point, but check if it is the same type brickToAttach.ActiveConnectionPointIndex = BrickLibrary.Instance.getConnectionNextPreferedIndex(fixedBrick.PartNumber, fixedBrick.ActiveConnectionPointIndex); // check that the connection type is the same isActiveConnectionPointChosen = (brickToAttach.ActiveConnectionPoint.Type == fixedConnexionType) && brickToAttach.ActiveConnectionPoint.IsFree; } // if we didn't find any valid active connexion point, set the active connection // with the first connexion of the same type that we can find (if the brick as any connection point) if (!isActiveConnectionPointChosen) for (int i = 0; i < brickToAttach.ConnectionPoints.Count; ++i) if ((brickToAttach.ConnectionPoints[i].Type == fixedConnexionType) && brickToAttach.ConnectionPoints[i].IsFree) { brickToAttach.ActiveConnectionPointIndex = i; break; } }
/// <summary> /// Compute and return the angle that should take the brickToAttach if it is connected to the /// fixedBrick with both the specified connection point. /// </summary> /// <param name="fixedBrick">The brick on the map that doesn't move</param> /// <param name="connectionIndexForFixedBrick">the fixed brick's connection index that you want to use to compute the orientaion</param> /// <param name="brickToAttach">The brick to add for which we should compute the angle</param> /// <param name="connectionIndexForBrickToAttach">the attached brick's connection index that you want to use to compute the orientaion</param> /// <returns>The absolute orientation that should have the brick to attach to be correctly connected to the fixed brick (in degree)</returns> public static float sGetOrientationOfConnectedBrick(LayerBrick.Brick fixedBrick, int connectionIndexForFixedBrick, LayerBrick.Brick brickToAttach, int connectionIndexForBrickToAttach) { // compute the rotation float newOrientation = fixedBrick.Orientation + BrickLibrary.Instance.getConnectionAngleDifference(fixedBrick.PartNumber, connectionIndexForFixedBrick, brickToAttach.PartNumber, connectionIndexForBrickToAttach); // clamp the orientation between 0 and 360 if (newOrientation >= 360.0f) newOrientation -= 360.0f; if (newOrientation < 0.0f) newOrientation += 360.0f; // return the value return newOrientation; }
private int mNextPreferedActiveConnectionIndex = 0; // the prefered active connection index according to the brick library /// <summary> /// Add a new named group which has the specified partNumber on the specifier layer, and connected it to /// the specified selectedItem (part or group) using the specified wanted connection for that new part. /// </summary> /// <param name="layer">The layer on which to add the group, and in which the selectedItem is selected</param> /// <param name="selectedItem">The single selected item (this can be a single part or a single group). This parameter cannot be null.</param> /// <param name="partNumber">The number of the named group to add</param> /// <param name="wantedConnexion">The connection index of the group to add that should be used to connect to the selected item, or -1 if you don't care.</param> public AddConnectGroup(LayerBrick layer, Layer.LayerItem selectedItem, string partNumber, int wantedConnexion) { // the selected item should not be null System.Diagnostics.Debug.Assert(selectedItem != null); // save the layer and construct the group mBrickLayer = layer; mGroup = new Layer.Group(partNumber); // get the flat list of bricks from the hierarchical group mBricksInTheGroup = mGroup.getAllLeafItems(); // get the connectable brick among the selection, and also the selected item (in case the selected item is a single group without connections points) LayerBrick.Brick selectedBrick = layer.getConnectableBrick(); LayerBrick.Brick brickToConnectInAddedGroup = null; // check if we can attach the group to the unique selected object if ((selectedBrick != null) && selectedBrick.HasConnectionPoint) { // find the brick of the group that will be connected to the selected brick brickToConnectInAddedGroup = findBrickToConnectAndSetBestConnectionPointIndex(selectedItem, ref wantedConnexion); } // check if the brick to connect is valid and has connection point if ((brickToConnectInAddedGroup != null) && brickToConnectInAddedGroup.HasConnectionPoint) { // after setting the active connection point index from which this brick will be attached, // get the prefered index from the library mNextPreferedActiveConnectionIndex = BrickLibrary.Instance.getConnectionNextPreferedIndex(partNumber, wantedConnexion); // Compute the orientation of the bricks float newOrientation = AddConnectBrick.sGetOrientationOfConnectedBrick(selectedBrick, brickToConnectInAddedGroup); newOrientation -= brickToConnectInAddedGroup.Orientation; // Rotate all the bricks of the group first before translating RotateBrickOnPivotBrick rotateBricksAction = new RotateBrickOnPivotBrick(layer, mBricksInTheGroup, newOrientation, brickToConnectInAddedGroup); rotateBricksAction.MustUpdateBrickConnectivity = false; rotateBricksAction.redo(); // compute the translation to add to all the bricks PointF translation = new PointF(selectedBrick.ActiveConnectionPosition.X - brickToConnectInAddedGroup.ActiveConnectionPosition.X, selectedBrick.ActiveConnectionPosition.Y - brickToConnectInAddedGroup.ActiveConnectionPosition.Y); mGroup.translate(translation); } else { // and just compute the position to the right of the selected item PointF position = selectedItem.Position; position.X += selectedItem.DisplayArea.Width; mGroup.Position = position; // the reassing the selected brick with the first brick of the group if the selected item is a group // so that the brick index can correctly be set if (selectedItem.IsAGroup) { selectedBrick = (selectedItem as Layer.Group).getAllLeafItems()[0] as LayerBrick.Brick; } else { selectedBrick = selectedItem as LayerBrick.Brick; } } // set the index of the group in the list just after the selected brick if (selectedBrick != null) { mInsertIndex = layer.BrickList.IndexOf(selectedBrick) + 1; } }
public RotateAndMoveBrick(LayerBrick layer, List <Layer.LayerItem> bricks, float angle, LayerBrick.Brick pivotBrick, PointF move) : base(layer, bricks, angle, pivotBrick) { this.MustUpdateBrickConnectivity = false; // the connectivity will be updated by the move action mMoveAction = new MoveBrick(layer, bricks, move); }
public void add(LayerBrick.Brick.ConnectionPoint connection) { mFreeConnections[connection.Type].Add(connection); }
public void remove(LayerBrick.Brick.ConnectionPoint connection) { mFreeConnections[connection.Type].Remove(connection); }
/// <summary> /// This function try different strategy to find the best connection point to use on the specified grabbed part /// to start the flex chain. It is assumed that the grab part only have two connection, then: /// 1) if one connection is flexible and not the other, return this one, /// 2) else if one connection leads to a flexible connection and not the other, return this one /// 3) else if one connection is connected to a brick part of the track list and not the other, return this one, /// 4) else if both connections are or lead to a flexible one, return the connection closest to the mouse click /// 5) else if no connection are or lead to a flexible one, return null (no flexible chain can be created) /// </summary> /// <param name="trackList">A set of track hopefully connected together, and hopefully containing flex track</param> /// <param name="grabbedTrack">The part which will try to reach the target. It should be part of the list.</param> /// <param name="mouseCoordInStud">the coordinate of the mouse in stud coord</param> /// <returns>The best connection point of the grabbed part or null</returns> private LayerBrick.Brick.ConnectionPoint findStartingConnectionPoint(List<Layer.LayerItem> trackList, LayerBrick.Brick grabbedTrack, PointF mouseCoordInStud) { // try to find the best first connection point which will be the end target of the flex. LayerBrick.Brick.ConnectionPoint grabbedFirstConnection = grabbedTrack.ConnectionPoints[0]; LayerBrick.Brick.ConnectionPoint grabbedSecondConnection = grabbedTrack.ConnectionPoints[1]; // by preference choose the not flexible connection on the grabbed part float firstHingeAngle = BrickLibrary.Instance.getConnexionHingeAngle(grabbedFirstConnection.Type); float secondHingeAngle = BrickLibrary.Instance.getConnexionHingeAngle(grabbedSecondConnection.Type); if (firstHingeAngle != 0.0f && secondHingeAngle == 0.0f) return grabbedSecondConnection; else if (firstHingeAngle == 0.0f && secondHingeAngle != 0.0f) return grabbedFirstConnection; else if (firstHingeAngle == 0.0f && secondHingeAngle == 0.0f) { // neither connection are flexibles on the grab part, so we choose the connection that // do not lead to a flexible part (and the other connection does) bool firstConnectionLeadToFlexiblePart = false; bool secondConnectionLeadToFlexiblePart = false; LayerBrick.Brick.ConnectionPoint firstConnectionLead = grabbedFirstConnection; LayerBrick.Brick.ConnectionPoint secondConnectionLead = grabbedSecondConnection; // use a clone of the track list because we will remove the tested track to avoid infinite loop // in case of a close track chain List<Layer.LayerItem> remaingTrackToTestList = new List<Layer.LayerItem>(trackList); while ((!firstConnectionLeadToFlexiblePart || !secondConnectionLeadToFlexiblePart) && (firstConnectionLead != null || secondConnectionLead != null)) { // check if the leading bricks are in the trask list otherwise stop to follow the lead LayerBrick.Brick firstBrickLead = (firstConnectionLead != null) ? firstConnectionLead.mMyBrick : null; LayerBrick.Brick secondBrickLead = (secondConnectionLead != null) ? secondConnectionLead.mMyBrick : null; if (!remaingTrackToTestList.Contains(firstBrickLead)) firstConnectionLead = null; if (!remaingTrackToTestList.Contains(secondBrickLead)) secondConnectionLead = null; // remove those check brick from the list. Do it after and not in the if because first and second brick // may be the same and flexible, so it could be unfair to the second test remaingTrackToTestList.Remove(firstBrickLead); remaingTrackToTestList.Remove(secondBrickLead); // set the flag and follow the lead for the two leads followConnectionToFindFlexiblePart(ref firstConnectionLead, ref firstConnectionLeadToFlexiblePart); followConnectionToFindFlexiblePart(ref secondConnectionLead, ref secondConnectionLeadToFlexiblePart); } // either the loop is finished because we found flexible part on both side, or because we // finished to explore the two paths. Check if we have only one side leading to a flexible part // and choose the other one, otherwise go to the default method if (firstConnectionLeadToFlexiblePart && !secondConnectionLeadToFlexiblePart) return grabbedSecondConnection; else if (!firstConnectionLeadToFlexiblePart && secondConnectionLeadToFlexiblePart) return grabbedFirstConnection; else if (!firstConnectionLeadToFlexiblePart && !secondConnectionLeadToFlexiblePart) return null; // neither connection lead to a flexible part } // both connection of the grab part are flexibles, or both side of the grab part // lead to a flexible part, so we choose the connection which neighboor is not in the list bool isGrabbedFirstNeighborInList = trackList.Contains(grabbedFirstConnection.ConnectedBrick); bool isGrabbedSecondNeighborInList = trackList.Contains(grabbedSecondConnection.ConnectedBrick); if (isGrabbedFirstNeighborInList && !isGrabbedSecondNeighborInList) return grabbedSecondConnection; else if (!isGrabbedFirstNeighborInList && isGrabbedSecondNeighborInList) return grabbedFirstConnection; else { // both or neither neighboor are in the list, so we choose the closest connection to the mouse PointF distToFirstConnection = new PointF(grabbedFirstConnection.PositionInStudWorldCoord.X - mouseCoordInStud.X, grabbedFirstConnection.PositionInStudWorldCoord.Y - mouseCoordInStud.Y); PointF distToSecondConnection = new PointF(grabbedSecondConnection.PositionInStudWorldCoord.X - mouseCoordInStud.X, grabbedSecondConnection.PositionInStudWorldCoord.Y - mouseCoordInStud.Y); float squareDistToFirstConnection = (distToFirstConnection.X * distToFirstConnection.X) + (distToFirstConnection.Y * distToFirstConnection.Y); float squareDistToSecondConnection = (distToSecondConnection.X * distToSecondConnection.X) + (distToSecondConnection.Y * distToSecondConnection.Y); if (squareDistToFirstConnection < squareDistToSecondConnection) return grabbedFirstConnection; else return grabbedSecondConnection; } }
public RotateBrickOnPivotBrick(LayerBrick layer, List <Layer.LayerItem> bricks, float angle, LayerBrick.Brick pivotBrick) : base(layer, bricks, angle) { mPivotBrick = pivotBrick; }
public FindForm() { InitializeComponent(); // get the selected layer because we will need it Layer selectedLayer = Map.Instance.SelectedLayer; // determines which radio button should be selected bool isSelectionEmpty = (selectedLayer.SelectedObjects.Count == 0); this.inCurrentSelectionRadioButton.Checked = !isSelectionEmpty; this.inCurrentSelectionRadioButton.Enabled = !isSelectionEmpty; this.inLayerRadioButton.Checked = isSelectionEmpty; inLayerRadioButton_CheckedChanged(this.inLayerRadioButton, null); // fill the layer list (in reverse order) for (int i = Map.Instance.LayerList.Count - 1; i >= 0; --i) { Layer layer = Map.Instance.LayerList[i]; if (layer is LayerBrick) { // add a check box item and the corresponding layer reference in a private list this.LayerCheckedListBox.Items.Add(layer.Name, layer == selectedLayer); mBrickOnlyLayerList.Add(layer as LayerBrick); } } // construct the list of parts from the selection (if it is a valid selection) LayerBrick selectedBrickLayer = selectedLayer as LayerBrick; if ((selectedBrickLayer != null) && (selectedLayer.SelectedObjects.Count > 0)) { // collapse all the selection in a dictionnary with unique instance of each part // and a counter of each different part in the selection Dictionary <string, int> collaspedList = new Dictionary <string, int>(); foreach (Layer.LayerItem item in selectedLayer.SelectedObjects) { // add the item addPartToBuildingDictionnary(ref collaspedList, item.PartNumber); // and also add its named parents List <Layer.LayerItem> namedParents = item.NamedParents; foreach (Layer.LayerItem parent in namedParents) { addPartToBuildingDictionnary(ref collaspedList, parent.PartNumber); } } // construct the list by expanding the dictionnary // and at the same time find the best part (the one which higher occurence) int j = 0; int bestScore = 0; mSelectionPartList = new string[collaspedList.Count]; foreach (KeyValuePair <string, int> keyValue in collaspedList) { mSelectionPartList[j++] = keyValue.Key; if (keyValue.Value > bestScore) { bestScore = keyValue.Value; mBestPartToFindInSelection = keyValue.Key; } } } // fill the find and replace combo box if (mSelectionPartList != null) { this.FindComboBox.Items.AddRange(mSelectionPartList); } else { this.FindComboBox.Items.AddRange(mLibraryPartList); } this.ReplaceComboBox.Items.AddRange(mLibraryPartList); setBestSelectedItemForFindComboBox(); // update the check all button according to the number of layer checked // the function to update the status of the button will be called by the event handler LayerCheckedListBox_SelectedIndexChanged(null, null); }
/// <summary> /// Call this function when you want to attach the current control point to the specified brick. /// Be sure to choose the correct current point before calling this function. /// </summary> /// <param name="index">the index of the control point to attach</param> /// <param name="brick">the brick to which the current control point will be attached</param> public override void attachControlPointToBrick(int index, LayerBrick.Brick brick) { mControlPoint[index].mAttachedBrick = brick; }
/// <summary> /// Call this function when you want to attach the current control point to the specified brick. /// Be sure to choose the correct current point before calling this function /// </summary> /// <param name="index">the index of the control point to attach</param> /// <param name="brick">the brick to which the current control point will be attached</param> public abstract void attachControlPointToBrick(int index, LayerBrick.Brick brick);
/// <summary> /// Try to reach the specify target position with this chain /// </summary> /// <param name="targetInWorldStudCoord">the target position in world stud coord</param> /// <param name="targetConnection">If the end of the flex chain need to be connected to a connection, this parameter indicates which one, otherwise it is null</param> public void reachTarget(PointF targetInWorldStudCoord, LayerBrick.Brick.ConnectionPoint targetConnection) { // save the primary target mPrimaryTarget = targetInWorldStudCoord; // check if we need to compute a second target position mUseTwoTargets = (targetConnection != null); if (mUseTwoTargets) { // rotate the second target vector according to the orientation of the snapped connection PointF[] translation = { mLastBoneVector }; Matrix rotation = new Matrix(); rotation.Rotate(targetConnection.mMyBrick.Orientation + targetConnection.Angle + 180); rotation.TransformVectors(translation); // translate the target with the rotated vector for the second target mSecondaryTarget.X = targetInWorldStudCoord.X + translation[0].X; mSecondaryTarget.Y = targetInWorldStudCoord.Y + translation[0].Y; } // reset the status flag mCurrentUpdateStatus = IKSolver.CCDResult.Processing; // and call the update method update(); }
private LayerBrick.Brick findBrickToConnectAndSetBestConnectionPointIndex(Layer.LayerItem fixedItem, ref int wantedConnexion) { // the brick that will be used to attach the group LayerBrick.Brick brickToAttach = null; int originalWantedConnexion = wantedConnexion; // memorize the original wanted connection in case we need to reset it // get the type of the active connexion of the selected brick Layer.Group fixedGroup = fixedItem as Layer.Group; int fixedConnexionType = (fixedGroup != null) ? fixedGroup.ActiveConnectionPoint.Type : (fixedItem as LayerBrick.Brick).ActiveConnectionPoint.Type; // first connect all the connection inside the group. Normally the connection of the bricks of the group // are done directly on the layer, afer that the brick has been added. But here we need to connect the bricks // inisde the group, in order to check the free remaining connections LayerBrick.updateBrickConnectivityForASpareSetOfBrickAmongThemselve(mBricksInTheGroup); // try to give the correct connexion point, either the specified wanted one, or if // we add the same brick do a special case bool isActiveConnectionPointChosen = false; if (wantedConnexion >= 0) { // set the active connexion point with the wanted one brickToAttach = setActiveConnectionIndex(wantedConnexion); // check that the wanted connection type is the same as the selected brick isActiveConnectionPointChosen = (brickToAttach != null) && (brickToAttach.ActiveConnectionPoint.Type == fixedConnexionType) && brickToAttach.ActiveConnectionPoint.IsFree; } else if ((fixedGroup != null) && (fixedGroup.PartNumber == mGroup.PartNumber)) { // check if the new added brick is the same kind of the selected one, if so, // then we choose the previous connection point, but check if it is the same type wantedConnexion = BrickLibrary.Instance.getConnectionNextPreferedIndex(fixedGroup.PartNumber, fixedGroup.ActiveConnectionIndex); brickToAttach = setActiveConnectionIndex(wantedConnexion); // check that the connection type is the same isActiveConnectionPointChosen = (brickToAttach != null) && (brickToAttach.ActiveConnectionPoint.Type == fixedConnexionType) && brickToAttach.ActiveConnectionPoint.IsFree; } // if we didn't find any valid active connexion point, set the active connection // with the first connexion of the same type that we can find (if the brick as any connection point) if (!isActiveConnectionPointChosen) { wantedConnexion = 0; foreach (Layer.LayerItem item in mBricksInTheGroup) { LayerBrick.Brick brick = item as LayerBrick.Brick; if (brick.HasConnectionPoint) { for (int i = 0; i < brick.ConnectionPoints.Count; ++i) { if ((brick.ConnectionPoints[i].Type == fixedConnexionType) && brick.ConnectionPoints[i].IsFree) { brick.ActiveConnectionPointIndex = i; brickToAttach = brick; isActiveConnectionPointChosen = true; break; } // increase the connection count ++wantedConnexion; } } // break again if we found it if (isActiveConnectionPointChosen) { break; } } } // if we still didn't find a compatible brick, reset the wanted connection that we have modified if (!isActiveConnectionPointChosen) { wantedConnexion = originalWantedConnexion; } // finally return the brick selected for the attachement return(brickToAttach); }
public ReplaceBrick(List <LayerBrick> layerList, string partNumberToReplace, string newPartNumber, bool replaceInSelectionOnly) { // store the list of layer for which this action apply and create a list of the same size for the bricks mBrickLayerList = layerList; mPartNumberToReplace = partNumberToReplace; mBrickPairList = new List <List <BrickPair> >(layerList.Count); // use a counter of brick replaced, to avoid exceeding the budget int replacedBrickCount = 0; // iterate on all the layers foreach (LayerBrick layer in layerList) { // memorize the layer that has the selected bricks if (layer.SelectedObjects.Count > 0) { mLayerWhereToSelectTheReplacedBricks = layer; } // add the list of brick pair (that can stay empty if no brick is found in that layer) List <BrickPair> currentPairList = new List <BrickPair>(); mBrickPairList.Add(currentPairList); // compute the list of bricks on which we should iterate List <Layer.LayerItem> itemsToReplace = null; if (replaceInSelectionOnly) { itemsToReplace = computeListOfItemToReplace(layer.SelectedObjects); } else { itemsToReplace = computeListOfItemToReplace(layer.BrickList); } // iterate on all the bricks of the layer or on the selection to find the brick to replace foreach (Layer.LayerItem item in itemsToReplace) { // increase the count of brick to replace replacedBrickCount++; // then check if we can add the brick if (Budget.Budget.Instance.canAddBrick(newPartNumber, replacedBrickCount, true)) { // create the new item Layer.LayerItem newItem = createReplacementBrick(item, newPartNumber); // create the pair and add it to the list BrickPair brickPair = new BrickPair(item, newItem); currentPairList.Add(brickPair); // check if we also need to add this pair to the list of brick to reselect if (layer.SelectedObjects.Contains(item)) { mReplacedBricksToSelect.Add(brickPair); } } else { // beep if we reach the limit Map.Instance.giveFeedbackForNotAddingBrick(Map.BrickAddability.YES_AND_NO_REPLACEMENT_LIMITED_BY_BUDGET); // no need to continue if we cannot add more bricks, so stop the iteration mIsLimitedByBudget = true; break; } } // stop iterating on the layer if we reach the limit if (mIsLimitedByBudget) { break; } } }
/// <summary> /// Compute and return the angle that should take the brickToAttach if it is connected to the /// fixedBrick with both their respective active connection point. /// </summary> /// <param name="fixedBrick">The brick on the map that doesn't move</param> /// <param name="brickToAttach">The brick to add for which we should compute the angle</param> /// <returns>The absolute orientation that should have the brick to attach to be correctly connected to the fixed brick (in degree)</returns> public static float sGetOrientationOfConnectedBrick(LayerBrick.Brick fixedBrick, LayerBrick.Brick brickToAttach) { return sGetOrientationOfConnectedBrick(fixedBrick, fixedBrick.ActiveConnectionPointIndex, brickToAttach, brickToAttach.ActiveConnectionPointIndex); }
public BrickTransform(LayerBrick.Brick brick, PointF position, float orientation) { mBrick = brick; mPosition = position; mOrientation = orientation; }
/// <summary> /// Call this function when you want to attach the current control point to the specified brick. /// Be sure to choose the correct current point before calling this function /// </summary> /// <param name="index">useless for circular ruler</param> /// <param name="brick">the brick to which the current control point will be attached</param> public override void attachControlPointToBrick(int index, LayerBrick.Brick brick) { // the circular ruler only have one attach mAttachedBrick = brick; }
private void ReplaceButton_Click(object sender, EventArgs e) { List <LayerBrick> layers = null; // check if the selection must be performed in the current selection // or in several layers if (this.inCurrentSelectionRadioButton.Checked) { // only one layer is selected layers = new List <LayerBrick>(1); // get the current selected layer because we will need it (normally it is never null) LayerBrick selectedLayer = (Map.Instance.SelectedLayer) as LayerBrick; if (selectedLayer != null) { layers.Add(selectedLayer); } } else { layers = new List <LayerBrick>(this.LayerCheckedListBox.CheckedIndices.Count); foreach (int index in this.LayerCheckedListBox.CheckedIndices) { layers.Add(mBrickOnlyLayerList[index]); } } // get the search and replace part number string searchingPartNumber = this.FindComboBox.SelectedItem as string; string replacementPartNumber = this.ReplaceComboBox.SelectedItem as string; // create the action Actions.Bricks.ReplaceBrick replaceAction = new Actions.Bricks.ReplaceBrick(layers, searchingPartNumber, replacementPartNumber, this.inCurrentSelectionRadioButton.Checked); // check if there was a budget limitation and if the user cancel the action bool canDoTheAction = true; if (Settings.Default.DisplayWarningMessageForBrickNotReplacedDueToBudgetLimitation && replaceAction.IsLimitedByBudget) { // if some brick cannot be replaced, display a warning message // use a local variable to get the value of the checkbox, by default we don't suggest the user to hide it bool dontDisplayMessageAgain = false; // display the warning message DialogResult result = ForgetableMessageBox.Show(BlueBrick.MainForm.Instance, Properties.Resources.ErrorMsgSomeBrickWereNotReplacedDueToBudgetLimitation, Properties.Resources.ErrorMsgTitleWarning, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1, ref dontDisplayMessageAgain); // set back the checkbox value in the settings (don't save the settings now, it will be done when exiting the application) Properties.Settings.Default.DisplayWarningMessageForBrickNotReplacedDueToBudgetLimitation = !dontDisplayMessageAgain; // change the action flag depending of the answer of the user canDoTheAction = (result == DialogResult.Yes); } // do the action if we should if (canDoTheAction) { Actions.ActionManager.Instance.doAction(replaceAction); } // close the window this.Close(); }
/// <summary> /// Create a flex chain from a set of brick given a starting brick. From the free connection point /// of this starting brick go through all the linked connection points while the brick only have /// two connections. If the brick has only one or more than 2 connection (like a joint or crossing) /// we stop the chain. /// </summary> /// <param name="trackList">A set of track hopefully connected together, and hopefully containing flex track</param> /// <param name="grabbedTrack">The part which will try to reach the target. It should be part of the list.</param> /// <param name="currentFirstConnection">The first connection from which to start, which can be null and belongs to the grabbed track</param> public void ceateFlexChain(List<Layer.LayerItem> trackList, LayerBrick.Brick grabbedTrack, LayerBrick.Brick.ConnectionPoint currentFirstConnection) { // init all the arrays int boneCount = trackList.Count; mBoneList = new List<IKSolver.Bone_2D_CCD>(boneCount); mFlexChainList = new List<ChainLink>(boneCount * 2); mBricksInTheFlexChain = new List<Layer.LayerItem>(boneCount); // start to iterate from the grabbed track LayerBrick.Brick currentBrick = grabbedTrack; ChainLink hingedLink = null; addNewBone(currentFirstConnection, grabbedTrack, 0.0); // continue to iterate until we reach the end (no current brick) or the end of the selection // and continue only if the chain is made with track that exclusively has 2 connections to make a chain // (or one for the first iteration). while ((currentBrick != null) && trackList.Contains(currentBrick) && ((currentFirstConnection == null) || (currentBrick.ConnectionPoints.Count == 2))) { // get the other connection on the current brick int secondIndex = (currentBrick.ConnectionPoints[0] == currentFirstConnection) ? 1 : 0; LayerBrick.Brick.ConnectionPoint currentSecondConnection = currentBrick.ConnectionPoints[secondIndex]; LayerBrick.Brick nextBrick = currentSecondConnection.ConnectedBrick; LayerBrick.Brick.ConnectionPoint nextFirstConnection = currentSecondConnection.ConnectionLink; // add the two connections of the brick ChainLink link = new ChainLink(nextFirstConnection, currentSecondConnection); mFlexChainList.Insert(0, link); // check if the connection can rotate (if it is an hinge) float hingeAngle = BrickLibrary.Instance.getConnexionHingeAngle(currentSecondConnection.Type); if (hingeAngle != 0.0f) { // advance the hinge conncetion hingedLink = link; // add the link in the list addNewBone(currentSecondConnection, currentBrick, hingeAngle); // compute the current angle between the hinge connection and set it to the current bone // to do that we use the current angle between the connected brick and remove the static angle between them // to only get the flexible angle. float angleInDegree = 0.0f; if (nextBrick != null) angleInDegree = simplifyAngle(nextBrick.Orientation - currentBrick.Orientation - link.mAngleBetween); mBoneList[0].localAngleInRad = angleInDegree * (Math.PI / 180); // save the initial static cumulative orientation: start with the orientation of the root brick // if the hinge is connected to a brick, otherwise, if the hinge is free (connected to the world) // use the orientation of the hinge brick. // we set the value several time in the loop, in order to set it with the brick directly // connected to the last hinge in the chain if (nextBrick != null) mInitialStaticCumulativeOrientation = -nextBrick.Orientation; else mInitialStaticCumulativeOrientation = -currentBrick.Orientation; } // advance to the next link currentBrick = nextBrick; currentFirstConnection = nextFirstConnection; // check if the track is not a loop, otherwise we will have an infinite loop. // but don't add the test in the while because the first iteration must pass if (currentBrick == grabbedTrack) break; } // store the root hinge connection index (the last hinge found is the flexible root) if (hingedLink != null) mRootHingedLinkIndex = mFlexChainList.IndexOf(hingedLink); // compute the last bone vector if there is enough bones if (mBoneList.Count > 2) { int lastIndex = mBoneList.Count - 1; int beforeLastIndex = lastIndex - 1; mLastBoneVector = new PointF((float)(mBoneList[beforeLastIndex].worldX - mBoneList[lastIndex].worldX), (float)(mBoneList[beforeLastIndex].worldY - mBoneList[lastIndex].worldY)); // rotate the vector such as to compute it for a null angle // but if the last bone doesn't have connection, it can never snap, so the last bone will never be used if (mBoneList[lastIndex].connectionPoint != null) { PointF[] translation = { mLastBoneVector }; Matrix rotation = new Matrix(); rotation.Rotate(mBoneList[lastIndex].connectionPoint.mMyBrick.Orientation); rotation.TransformVectors(translation); mLastBoneVector = translation[0]; } } // add the current brick in the list of bricks, by not going further than the root brick LayerBrick.Brick.ConnectionPoint rootConnection = mFlexChainList[mRootHingedLinkIndex].mFirstConnection; if (rootConnection.mMyBrick != null) mBricksInTheFlexChain.Add(rootConnection.mMyBrick); for (int i = mRootHingedLinkIndex; i < mFlexChainList.Count; ++i) mBricksInTheFlexChain.Add(mFlexChainList[i].mSecondConnection.mMyBrick); }
private void MapPanel_DragDrop(object sender, DragEventArgs e) { if (mCurrentPartDrop != null) { // we have finished a dragndrop, remove the temporary part if (mBrickLayerThatReceivePartDrop != null) { mBrickLayerThatReceivePartDrop.removeTemporaryPartDrop(mCurrentPartDrop); mBrickLayerThatReceivePartDrop = null; } // and add the real new part Map.Instance.addBrick(mCurrentPartDrop); // reset the dropping part number here and there mCurrentPartDrop = null; (this.TopLevelControl as MainForm).resetDraggingPartNumberInPartLib(); // refresh the view updateView(); // and give the focus to the map panel such as if the user use the wheel to zoom // just after after the drop, the zoom is performed instead of the part lib scrolling this.Focus(); } else { // if it is not a string, call the drag enter of the main app (this.TopLevelControl as MainForm).MainForm_DragDrop(sender, e); } }
private void addNewBone(LayerBrick.Brick.ConnectionPoint connection, LayerBrick.Brick brick, double maxAngleInDeg) { IKSolver.Bone_2D_CCD newBone = new IKSolver.Bone_2D_CCD(); newBone.maxAbsoluteAngleInRad = maxAngleInDeg * (Math.PI / 180); if (connection != null) { newBone.worldX = connection.PositionInStudWorldCoord.X; newBone.worldY = -connection.PositionInStudWorldCoord.Y; // BlueBrick use an indirect coord sys, and the IKSolver a direct one } else { newBone.worldX = brick.Center.X; newBone.worldY = -brick.Center.Y; // BlueBrick use an indirect coord sys, and the IKSolver a direct one } newBone.connectionPoint = connection; mBoneList.Insert(0, newBone); }
private void MapPanel_DragEnter(object sender, DragEventArgs e) { // if the number of click is null, that means it can be a dragndrop from another view, such as the part lib // check if we need to search the image dropped, or if we already have it if (mCurrentPartDrop == null) { // by default do not accept the drop e.Effect = DragDropEffects.None; // ask the main window if one part was selected in the part lib // because the getData from the event doesn't work well under mono, normally it should be: e.Data.GetData(DataFormats.SystemString) as string string partDropNumber = (this.TopLevelControl as MainForm).getDraggingPartNumberInPartLib(); // check if we can add it Map.BrickAddability canAdd = Map.Instance.canAddBrick(partDropNumber); if (canAdd == Map.BrickAddability.YES) { mBrickLayerThatReceivePartDrop = Map.Instance.SelectedLayer as LayerBrick; if (partDropNumber != null && mBrickLayerThatReceivePartDrop != null) { if (BrickLibrary.Instance.isAGroup(partDropNumber)) mCurrentPartDrop = new Layer.Group(partDropNumber); else mCurrentPartDrop = new LayerBrick.Brick(partDropNumber); mBrickLayerThatReceivePartDrop.addTemporaryPartDrop(mCurrentPartDrop); // set the effect in order to get the drop event e.Effect = DragDropEffects.Copy; } } else Map.Instance.giveFeedbackForNotAddingBrick(canAdd); } // check again if we are not dragging a part, maybe we drag a file if (mCurrentPartDrop == null) (this.TopLevelControl as MainForm).MainForm_DragEnter(sender, e); }
/// <summary> /// read and set the two parameter to follow a chain of brick until we found a flexible part. This function only /// advance the search for one step (one link). /// </summary> /// <param name="connectionLead">the current connection point, from which we need to find the next one</param> /// <param name="isConnectionLeadingToFlexiblePart">a flag to tell if a flexible brick is found</param> private void followConnectionToFindFlexiblePart(ref LayerBrick.Brick.ConnectionPoint connectionLead, ref bool isConnectionLeadingToFlexiblePart) { if (connectionLead != null) { // set the flag if not already true isConnectionLeadingToFlexiblePart |= (BrickLibrary.Instance.getConnexionHingeAngle(connectionLead.Type) != 0.0f); // if we found a flexible part, stop following the path if (isConnectionLeadingToFlexiblePart) { connectionLead = null; // stop following this path } else { // jump to the attach brick accross the link (which may be null, in such case, the search will stop) connectionLead = connectionLead.ConnectionLink; // if there's a brick connected, check if it is a 2 connections brick and take the other if (connectionLead != null) { // get the list of connection point for the first leading brick List<LayerBrick.Brick.ConnectionPoint> connectionList = connectionLead.mMyBrick.ConnectionPoints; if (connectionList.Count == 2) { // check the next connections and set it int otherIndex = (connectionList[0] == connectionLead) ? 1 : 0; connectionLead = connectionList[otherIndex]; } else { // if it is a 0, 1 or 3 or more connections brick type, stop the search connectionLead = null; } } } } }
private void MapPanel_DragLeave(object sender, EventArgs e) { // if the user leave the panel while is was dropping a part, // just cancel the drop if (mCurrentPartDrop != null) { // remove and destroy the part if (mBrickLayerThatReceivePartDrop != null) { mBrickLayerThatReceivePartDrop.removeTemporaryPartDrop(mCurrentPartDrop); mBrickLayerThatReceivePartDrop = null; } mCurrentPartDrop = null; // update the view updateView(); } }
public ChainLink(LayerBrick.Brick.ConnectionPoint firstConnection, LayerBrick.Brick.ConnectionPoint secondConnection) { mFirstConnection = firstConnection; mSecondConnection = secondConnection; if (firstConnection != null) { int firstIndex = firstConnection.mMyBrick.ConnectionPoints.IndexOf(firstConnection); int secondIndex = secondConnection.mMyBrick.ConnectionPoints.IndexOf(secondConnection); mAngleBetween = BrickLibrary.Instance.getConnectionAngleDifference(secondConnection.mMyBrick.PartNumber, secondIndex, firstConnection.mMyBrick.PartNumber, firstIndex); } else { // if the first connection point is null, create a dummy connection point in the world, // at the position of the second connection and not attached to a brick. // The angle between is in that case of course null mFirstConnection = new LayerBrick.Brick.ConnectionPoint(secondConnection.PositionInStudWorldCoord); } }
public RotateBrick(LayerBrick layer, List <Layer.LayerItem> bricks, int rotateSteps) : this(layer, bricks, rotateSteps, false) { }
public RotateBrick(LayerBrick layer, List <Layer.LayerItem> bricks, float angle, bool forceKeepLastCenter) { commonConstructor(layer, bricks, angle, forceKeepLastCenter); }
public RotateBrick(LayerBrick layer, List <Layer.LayerItem> bricks, int rotateSteps, bool forceKeepLastCenter) { // compute the default rotation angle, used if no bricks in the list is connected to something else float angle = MapData.Layer.CurrentRotationStep * rotateSteps; // now check if we can find any brick in the list which is connected to another // brick not in the list: in that case we don't care about the rotation step, // we rotate the group of brick such as it can connect with its next connexion point. // we do this first because maybe it will invalidate the flag sLastCenterIsValid // first we gather all the free connections or those linked with bricks outside of the list of brick FreeConnectionSet externalConnectionSet = new FreeConnectionSet(); // all the connection connected to external bricks FreeConnectionSet availableConnectionSet = new FreeConnectionSet(); // all the possible connections that can be used to link to one external brick foreach (Layer.LayerItem item in bricks) { LayerBrick.Brick brick = item as LayerBrick.Brick; if (brick.HasConnectionPoint) { foreach (LayerBrick.Brick.ConnectionPoint connection in brick.ConnectionPoints) { if (connection.IsFree) { availableConnectionSet.add(connection); } else if (!bricks.Contains(connection.ConnectionLink.mMyBrick)) { availableConnectionSet.add(connection); externalConnectionSet.add(connection); } } } } // get the biggest group of external connection among all the available types, and also get its type int chosenConnexionType = BrickLibrary.ConnectionType.DEFAULT; List <LayerBrick.Brick.ConnectionPoint> externalConnectionList = externalConnectionSet.getBiggestList(out chosenConnexionType); // check if there is any external connection on which we should rotate if (externalConnectionList.Count > 0) { // in that case we don't use the static center sLastCenterIsValid = false; // for now, without a lot of imagination, take the first connection of the list mOldConnectionPoint = externalConnectionList[0]; // store the connection position mConnexionPosition = mOldConnectionPoint.PositionInStudWorldCoord; // get the fixed brick, the external brick on the other side of the chosen connection LayerBrick.Brick fixedBrick = mOldConnectionPoint.ConnectedBrick; int fixedBrickConnectionIndex = mOldConnectionPoint.ConnectionLink.Index; // get the same list but for available connections List <LayerBrick.Brick.ConnectionPoint> availableConnectionList = availableConnectionSet.getListForType(chosenConnexionType); // check in which direction and how many connection we should jump bool rotateCW = (rotateSteps < 0); int nbSteps = Math.Abs(rotateSteps); // get the index of the chosen connection in the available connection list int index = availableConnectionList.IndexOf(mOldConnectionPoint); // start from it then count forward or backward a certain number of connections // depending on the number of steps and the rotation direction if (rotateCW) { index -= (nbSteps % availableConnectionList.Count); if (index < 0) { index += availableConnectionList.Count; } } else { index += (nbSteps % availableConnectionList.Count); if (index >= availableConnectionList.Count) { index -= availableConnectionList.Count; } } // finally get the new connection from the chosen index mNewConnectionPoint = availableConnectionList[index]; // compute the angle to rotate LayerBrick.Brick newConnectedBrick = mNewConnectionPoint.mMyBrick; angle = AddConnectBrick.sGetOrientationOfConnectedBrick(fixedBrick, fixedBrickConnectionIndex, newConnectedBrick, mNewConnectionPoint.Index) - newConnectedBrick.Orientation; } // then call the normal constructor commonConstructor(layer, bricks, angle, forceKeepLastCenter); }