/// <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); } } }
/// <summary> /// construct a new node /// </summary> /// <param name="brick">the brick corresponding to this node</param> public AStarNode(LayerBrick.Brick brick) { mBrick = brick; }
public RulerAttachementSet(LayerBrick.Brick owner) { mOwnerBrick = owner; }
/// <summary> /// This function check all the electric circuit connected to the specified brick, starting from /// the specified brick. The startingBrick must have an ElectricCircuitIndexList not null. /// </summary> /// <param name="startingBrick">The brick to start from.</param> private static void checkFromOneBrick(LayerBrick.Brick startingBrick) { // the list of all the shortcut found List <LayerBrick.Brick.ConnectionPoint> shortcuts = new List <LayerBrick.Brick.ConnectionPoint>(); // clear the list and add the first node mBricksToExplore.Clear(); mBricksToExplore.Add(startingBrick); // init the first connection of the starting brick with the new timestamp LayerBrick.Brick.ConnectionPoint firstConnection = startingBrick.ConnectionPoints[startingBrick.ElectricCircuitIndexList[0].mIndex1]; firstConnection.Polarity = sTimeStamp; // if the first connection is connected to another brick, also add this brick in the list if (firstConnection.ConnectionLink != null) { firstConnection.ConnectionLink.Polarity = (short)(-sTimeStamp); mBricksToExplore.Add(firstConnection.ConnectedBrick); } //explore while the list is not empty while (mBricksToExplore.Count > 0) { // pop the first node of the list LayerBrick.Brick brick = mBricksToExplore[0]; mBricksToExplore.RemoveAt(0); // declare a boolean variable to check if during the exploration of all the circuits of the // brick, one was ignore. If yes and later we transfert electricity on the brick, we will // have to re-explore the brick for checking again the ignored circuits bool needToReexploreTheBrick = false; // iterate on all the brick connection if (brick.ElectricCircuitIndexList != null) { foreach (BrickLibrary.Brick.ElectricCircuit circuit in brick.ElectricCircuitIndexList) { // get the connection point of the current circuit inside the brick LayerBrick.Brick.ConnectionPoint start = brick.ConnectionPoints[circuit.mIndex1]; LayerBrick.Brick.ConnectionPoint end = brick.ConnectionPoints[circuit.mIndex2]; // check wich one has the incoming electricity, if it's not the start, // swap the two connections point in order to have only one algorithm in the following // after this swap, normally we should have the start +/-timestamp if (Math.Abs(end.Polarity) == sTimeStamp) { LayerBrick.Brick.ConnectionPoint swap = start; start = end; end = swap; } // transfert the time stamp from the start to the end if (Math.Abs(start.Polarity) == sTimeStamp) { // check if we have a shortcut in the current circuit. // If the end is already set with the same polarity than the start, we have a shortcut if (end.Polarity == start.Polarity) { // shortcut!! shortcuts.Add(start); } // else if no shorcut check if we didn't already transfer the electricity to the end else if (end.Polarity != -start.Polarity) { // the end connection was not explored yet, so we will set its timestamp and push // his neighbor for future exploration. // transfert the electricity to the end end.Polarity = (short)(-start.Polarity); // for complex part that has several circuit in it, if we transfert electricity // in a circuit, this circuit may also be linked to a previous one already iterated. // This is the case of the rail jonction point. The circuit 0 is for example the // straight line, whereas circuit 1, is the curved derivation. If the current comes // from circuit 1, then the circuit 0 was already ignored and must be re-tested. // So we reinsert the part if some circuit werz ignored on this part if (needToReexploreTheBrick) { mBricksToExplore.Insert(0, brick); needToReexploreTheBrick = false; } // add the neighbor if any LayerBrick.Brick.ConnectionPoint connectionLink = end.ConnectionLink; if (connectionLink != null) { // check if we have a shortcut if (connectionLink.Polarity == end.Polarity) { // shortcut!! shortcuts.Add(end); } // if no shortcut, check if we have to to explore the connection else if (connectionLink.Polarity != -end.Polarity) { // transfert the polarity to the linked connection connectionLink.Polarity = (short)(-end.Polarity); // and add the new brick in the list for furture exploration mBricksToExplore.Add(end.ConnectedBrick); } } } } else { // no electric current in this circuit. This may be the case with a part // with different independant circuit. // Maybe the circuits are linked, maybe they are independant, anyway, we // check the flag to tell that the brick need to be re-explored needToReexploreTheBrick = true; } } } } // set the polarity to 0 for all the connection where we found the shortcuts foreach (LayerBrick.Brick.ConnectionPoint connection in shortcuts) { connection.HasElectricShortcut = true; } }
public static List <Layer.LayerItem> findPath(LayerBrick.Brick startBrick, LayerBrick.Brick goalBrick) { List <Layer.LayerItem> result = new List <Layer.LayerItem>(); // init some variables sOpenList.Clear(); sCloseList.Clear(); // create the first node with the starting brick AStarNode currentNode = new AStarNode(startBrick); currentNode.ComputeParameters(goalBrick); // start of the loop while (currentNode != null) { // get the refernce of the current brick LayerBrick.Brick currentBrick = currentNode.mBrick; // check if we reached the goal if (currentBrick == goalBrick) { // the goal is reached, put all the bricks in the result list for (AStarNode node = currentNode; node != null; node = node.mParentNode) { result.Add(node.mBrick); } // reverse the list to have the path from start to goal result.Reverse(); return(result); } // now iterate on all the connexion point of the current brick List <LayerBrick.Brick.ConnectionPoint> connexionList = currentBrick.ConnectionPoints; if (connexionList != null) { foreach (LayerBrick.Brick.ConnectionPoint connexion in connexionList) { // check if the connexion is free, or if there is a brick connected to it LayerBrick.Brick neighborBrick = connexion.ConnectedBrick; if (neighborBrick == null) { continue; } // we found a valid connexion, create a new node for this new potential brick to explore AStarNode potentialNewNeighborNode = new AStarNode(neighborBrick); potentialNewNeighborNode.mParentNode = currentNode; potentialNewNeighborNode.ComputeParameters(goalBrick); // try to search the neighbor brick in the close list AStarNode neighborNode = sCloseList.Find(neighborBrick); if (neighborNode != null) { // we found this brick in the close list, that means this brick was already explored, // but we need to check if we found a shorter way, by checking the f values // so we check if the node stay where it is if (neighborNode.f <= potentialNewNeighborNode.f) { continue; // that's fine the previous exploration was the shorter way } // else we found a shorter way // so we remove the node from the close list (cause we will add it in open) sCloseList.Remove(neighborNode); } else { // the neighbor brick is not in the close list so now we check if it is in open list neighborNode = sOpenList.Find(neighborBrick); if (neighborNode != null) { // the brick is already in the open list but we check if we have found a shorter way // by checking the f values. if (neighborNode.f <= potentialNewNeighborNode.f) { continue; // that's fine the new way we found is not shorter } // else that mean the new way is shorter // so we remove the node from the open list (cause we will add the better one) sOpenList.Remove(neighborNode); } } // If we reach this point, that means the potential new node is valid and // must be added in the open list sOpenList.Add(potentialNewNeighborNode); } } // the current node is finished to be expored, so add it in the close list sCloseList.Add(currentNode); // get the next node to explore if (sOpenList.Count > 0) { currentNode = sOpenList[0]; sOpenList.RemoveAt(0); } else { currentNode = null; } } // the open list is empty and we didn't find the goal brick, so the search failed. return(result); }
/// <summary> /// Write a list of prefered connections. The list is computed as follow: /// First we get all the free connections in the whole group, then we split that /// list into sub-list per connection type, and then for each sub-list we create /// a loop of next connection preferences. /// For example if the group contains 4 track and 3 road connections, and the /// two track parts are connected, then we have only 2 free track connections /// and 3 free road connection. We will generate a first cycle for the track /// and a second cycle for the road. /// </summary> /// <param name="xmlWriter">The xmlWritter where to write the list</param> /// <param name="group">The group for which we are writting the list</param> private void writeGroupConnectionPreferenceList(XmlWriter xmlWriter, Layer.Group group) { // get all the bricks in a flat list (removing intermediate group) List <Layer.LayerItem> allBricks = group.getAllLeafItems(); // if the group doesn't contains brick, just early exit if ((allBricks.Count == 0) || !(allBricks[0] is LayerBrick.Brick)) { return; } // declare a dictionary of list of connections, to store all the connections separated by connection type (which is the key of the dictionnary) Dictionary <int, List <ConnectionAndIndex> > connectionsPerType = new Dictionary <int, List <ConnectionAndIndex> >(); // declare a global counter to count the connection index inside the group int connectionCounter = 0; // now, iterate on all the connections of all the bricks, and create separated list of free connection foreach (Layer.LayerItem item in allBricks) { LayerBrick.Brick brick = item as LayerBrick.Brick; if (brick.HasConnectionPoint) { foreach (LayerBrick.Brick.ConnectionPoint connection in brick.ConnectionPoints) { if (connection.IsFree) { // we found a free connection, check if the list for its type was already added in the dictionary if (!connectionsPerType.ContainsKey(connection.Type)) { connectionsPerType.Add(connection.Type, new List <ConnectionAndIndex>()); } // now get the list corresponding to the type List <ConnectionAndIndex> freeConnectionList = connectionsPerType[connection.Type]; // then add the connection in the list freeConnectionList.Add(new ConnectionAndIndex(connection, connectionCounter)); } // increase the connection counter, no matter if the current connection is free or not connectionCounter++; } } } // check if we found something if (connectionsPerType.Count > 0) { // write the header of the list xmlWriter.WriteStartElement("GroupConnectionPreferenceList"); // now iterate on the dictionary, and for each list, create a cycle foreach (KeyValuePair <int, List <ConnectionAndIndex> > connectionsOfOneType in connectionsPerType) { for (int i = 0; i < connectionsOfOneType.Value.Count; ++i) { // get the current and the next connection ConnectionAndIndex currentConnection = connectionsOfOneType.Value[i]; ConnectionAndIndex nextConnection = (i == connectionsOfOneType.Value.Count - 1) ? connectionsOfOneType.Value[0] : connectionsOfOneType.Value[i + 1]; // write the current prefered link xmlWriter.WriteStartElement("nextIndex"); xmlWriter.WriteAttributeString("from", currentConnection.mIndexInTheGroup.ToString()); xmlWriter.WriteValue(nextConnection.mIndexInTheGroup); xmlWriter.WriteEndElement(); // nextIndex } } xmlWriter.WriteEndElement(); // GroupConnectionPreferenceList } }
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); }
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; } }
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 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); }