public ConnectionPointsTransaction CreateRemoveConnectionPointsTransaction(Span <Vector2i> connectionPoints) { // Here we want to check for wires that should be merged as a result of removint the connection points. List <Wire> Added = new List <Wire>(); List <Wire> Deleted = new List <Wire>(); foreach (var connection in connectionPoints) { // There can only be four wires connected to this point Span <Wire> removedPointWires = stackalloc Wire[4]; int wiresFound = 0; foreach (var bWire in WiresList) { if (bWire.IsPointOnWire(connection)) { removedPointWires[wiresFound] = bWire; wiresFound++; } } if (wiresFound == 2) { // Here we should check if the two wires are going in the // same direction, and merge them if they are. Wire a = removedPointWires[0]; Wire b = removedPointWires[1]; if (a.Direction == b.Direction) { // Here we should merge these wires. Deleted.Add(a); Deleted.Add(b); var minPos = Vector2i.ComponentWiseMin(a.Pos, b.Pos); var maxPos = Vector2i.ComponentWiseMax(a.EndPos, b.EndPos); var diff = maxPos - minPos; Wire merged; merged.Direction = a.Direction; merged.Pos = minPos; merged.Length = diff.ManhattanDistance; Added.Add(merged); } } } // No changes, so we don't create wire changes for this. if (Added.Count == 0 && Deleted.Count == 0) { return(new ConnectionPointsTransaction(false, connectionPoints, null, null)); } // FIXME: We want to de-deplicate the changes // FIXME: We want to do something better for the first argument!!! // This will lead to 0 debuggability as it will look like connectionpoints // are zero length wires at the origin... // We probably want to create it's own transaction type return(new ConnectionPointsTransaction(false, connectionPoints, Deleted, Added)); }
public WireTransaction?CreateModifyWireTransaction(Wire modify, Wire modified) { // Here we need to consider the case where one of the points have moved // This means that the point that was should maybe trigger a merge // and that the new point should maybe trigger a split. // First thing is to find the point that is being moved Vector2i removedPosition; Vector2i addedPosition; if (modify.Pos == modified.Pos) { // They have the same start point so it's the end points that changed. removedPosition = modify.EndPos; addedPosition = modified.EndPos; } else { // They have the same end pos so it's the start point that changed. removedPosition = modify.Pos; addedPosition = modified.Pos; } List <Wire> Added = new List <Wire>(); List <Wire> Deleted = new List <Wire>(); // Remove the old wire and add the new one Deleted.Add(modify); Added.Add(modified); // Check merge at removed point { // There can only be three wires connected to this point Span <Wire> removedPointWires = stackalloc Wire[3]; int wiresFound = 0; foreach (var bWire in WiresList) { if (bWire == modify) { continue; } if (bWire.IsPointOnWire(removedPosition)) { removedPointWires[wiresFound] = bWire; wiresFound++; } } // Here we should check if we should merge the wiress if (wiresFound == 2) { Wire a = removedPointWires[0]; Wire b = removedPointWires[1]; if (a.Direction == b.Direction) { Deleted.Add(a); Deleted.Add(b); var minPos = Vector2i.ComponentWiseMin(a.Pos, b.Pos); var maxPos = Vector2i.ComponentWiseMax(a.EndPos, b.EndPos); var diff = maxPos - minPos; Wire merged; merged.Direction = a.Direction; merged.Pos = minPos; merged.Length = diff.ManhattanDistance; Added.Add(merged); } } } // Now that we have potentially merged the wires // we want to check if there is any wire on the // added point that should be split { foreach (var bWire in WiresList) { if (bWire == modify) { continue; } // If the new position is on this wire we want to split it if (bWire.IsPointInsideWire(addedPosition)) { // If the wires go in different direction we should split them. if (bWire.Direction != modified.Direction) { // The diff will be in non - zero in only one direction so this will work fine. var diff = addedPosition - bWire.Pos; Deleted.Add(bWire); Added.Add(new Wire(bWire.Pos, diff.ManhattanDistance, bWire.Direction)); Added.Add(new Wire(bWire.Pos + diff, bWire.Length - diff.ManhattanDistance, bWire.Direction)); // After we have done this there cannot be any more wires to split so we break break; } } } } return(new WireTransaction(modify, Deleted, Added)); }
public WireTransaction CreateRemoveWireTransaction(Wire wire) { // When removing a wire we want to check and see if there are // any wires that should be merged after the removal. // We can think wire removal as removing two connection points, // we don't need to think about the points inside of the wire // we are removing because there shouldn't be anything connecting there. List <Wire> Added = new List <Wire>(); List <Wire> Deleted = new List <Wire>(); // We are deleting this wire. Deleted.Add(wire); List <Wire> StartPosAffectedWires = new List <Wire>(); List <Wire> EndPosAffectedWires = new List <Wire>(); foreach (var bWire in WiresList) { // Ignore the wire we are removing. if (bWire == wire) { continue; } if (bWire.IsConnectionPoint(wire.Pos)) { StartPosAffectedWires.Add(bWire); } if (bWire.IsConnectionPoint(wire.EndPos)) { EndPosAffectedWires.Add(bWire); } } // Do some sanity checking to see that nothing is going horribly wrong. if (StartPosAffectedWires.Count > 3) { Console.WriteLine($"Warn: The removed wires start position connected to more than 3 wires. This should be impossible!\n{string.Join(", ", StartPosAffectedWires.Select(w => $"({w})"))}"); } if (EndPosAffectedWires.Count > 3) { Console.WriteLine($"Warn: The removed wires end position connected to more than 3 wires. This should be impossible!\n{string.Join(", ", EndPosAffectedWires.Select(w => $"({w})"))}"); } // Now we have a list of the wires that could be affected by this wire removal // We want to find the wires that should merge. These are the wires that // connect and have the same direction even after the wire we are removing // has been removed. // We are only ever going to merge wires if there are two of them, // and only if they are going in the same direction. if (StartPosAffectedWires.Count == 2) { Wire a = StartPosAffectedWires[0]; Wire b = StartPosAffectedWires[1]; if (a.Direction == b.Direction) { // Here we are going to do a merge. Deleted.Add(a); Deleted.Add(b); var minPos = Vector2i.ComponentWiseMin(a.Pos, b.Pos); var maxPos = Vector2i.ComponentWiseMax(a.EndPos, b.EndPos); var diff = maxPos - minPos; Wire merged; merged.Direction = a.Direction; merged.Pos = minPos; merged.Length = diff.ManhattanDistance; Added.Add(merged); } } if (EndPosAffectedWires.Count == 2) { Wire a = EndPosAffectedWires[0]; Wire b = EndPosAffectedWires[1]; if (a.Direction == b.Direction) { // Here we are going to do a merge. Deleted.Add(a); Deleted.Add(b); var minPos = Vector2i.ComponentWiseMin(a.Pos, b.Pos); var maxPos = Vector2i.ComponentWiseMax(a.EndPos, b.EndPos); var diff = maxPos - minPos; Wire merged; merged.Direction = a.Direction; merged.Pos = minPos; merged.Length = diff.ManhattanDistance; Added.Add(merged); } } // Add the changes to the transaction. return(new WireTransaction(wire, Deleted, Added)); }
public WireTransaction?CreateAddWireTransaction(Wire wire) { var wireEnd = wire.GetEndPosition(); List <Wire> Deleted = new List <Wire>(); List <Wire> Added = new List <Wire>(); // This dictionary maps wires to the point where they intersect this wire // If there exists a mapping but the value is null, that means both ends // of the wire are contained inside of the addeed wire. Dictionary <Wire, Vector2i?> SplitPoints = new Dictionary <Wire, Vector2i?>(); // First we get all of the points where we need to split the current wire foreach (var bWire in WiresList) { bool start = wire.IsPointOnWire(bWire.Pos); bool end = wire.IsPointOnWire(bWire.EndPos); if (start && end) { // Null indicates that both ends are contained in this wire SplitPoints[bWire] = null; } else if (start) { SplitPoints[bWire] = bWire.Pos; } else if (end) { SplitPoints[bWire] = bWire.EndPos; } } // FIXME: Add other split points like component connection points! // After we've found all of the intersection points we can check // if the ends of the added wire will split some other wire. // At the same time we check to see if there is a wire that // contains both ends of the wire we added. // In this case we shouldn't create or delete any wires because // then there will be two wires on the same space. Wire?containingWire = null; foreach (var bWire in WiresList) { // We check to see if the point is *inside* // the wire because if the new wire touches // the other wire at it's end point we don't // need to do anything to it. It's only if the // new point is on the inside of the wire that // we need to do anything. bool containedStart = false; if (bWire.IsPointInsideWire(wire.Pos)) { // We only care if the wires are going in different direction // as that means we should split the wire. // The case where they are going the same direction // will be handled in the next step. if (wire.Direction != bWire.Direction) { // The diff will be in non-zero in only one direction so this will work fine. var diff = wire.Pos - bWire.Pos; Deleted.Add(bWire); Added.Add(new Wire(bWire.Pos, diff.ManhattanDistance, bWire.Direction)); Added.Add(new Wire(bWire.Pos + diff, bWire.Length - diff.ManhattanDistance, bWire.Direction)); } containedStart = true; } if (bWire.IsPointInsideWire(wire.EndPos)) { if (wire.Direction != bWire.Direction) { // The diff will be in non-zero in only one direction so this will work fine. var diff = wire.EndPos - bWire.Pos; Deleted.Add(bWire); Added.Add(new Wire(bWire.Pos, diff.ManhattanDistance, bWire.Direction)); Added.Add(new Wire(bWire.Pos + diff, bWire.Length - diff.ManhattanDistance, bWire.Direction)); } // This means that both the start and the end point of this wire was contained // inside of bWire. So we basically shouldn't create any transaction.s if (containedStart) { containingWire = bWire; // We don't care about any more wires so it's fine to break. break; } } } // If the wire we are adding is entrierly contained within another wire // the addition won't change any state so we don't create a transaction for that. if (containingWire.HasValue) { // This addition wouldn't change any state. return(null); } List <Vector2i> Points = new List <Vector2i>(); // Now we should merge or remove wires that are going in the same direction as us. Wire mergedWire = wire; foreach (var(splitWire, location) in SplitPoints) { if (location == null) { // Both ends are contained. // So to merge we can just delete the contained wire. Console.WriteLine($"Wire ({splitWire}) was completely contained in ({wire}), so it was removed."); Deleted.Add(splitWire); continue; } else if (wire.Direction == splitWire.Direction) { // This means that we should merge the two wires. // We can do that by deleting the existing wire and // extending the wire we are adding to include that wire. var minPos = Vector2i.ComponentWiseMin(mergedWire.Pos, splitWire.Pos); var maxPos = Vector2i.ComponentWiseMax(mergedWire.EndPos, splitWire.EndPos); var diff = maxPos - minPos; Wire newMerged; newMerged.Direction = wire.Direction; newMerged.Pos = minPos; newMerged.Length = diff.ManhattanDistance; Console.WriteLine($"Merged ({splitWire}) with ({mergedWire}). Result: ({newMerged})"); mergedWire = newMerged; Deleted.Add(splitWire); } else { // This will not fail due to the null check above. Console.WriteLine($"The wire ({splitWire}) should split the current wire at ({location})."); if (Points.Contains(location.Value) == false) { Points.Add(location.Value); } } } // Lastly we split the merged wire on all of the remaining points. // We do this by first sorting the points in the wires direction // and then go through linearly and add the parts of the wire. // We do the comparison outside of the lambda to avoid a capture. // (this is a premature optimization) Points.Sort( wire.Direction == Direction.Vertical ? (Comparison <Vector2i>)((v1, v2) => v1.Y - v2.Y) : ((v1, v2) => v1.X - v2.X)); Vector2i pos = mergedWire.Pos; foreach (var split in Points) { Wire newWire; newWire.Direction = mergedWire.Direction; newWire.Pos = pos; newWire.Length = (split - pos).ManhattanDistance; if (newWire.Length < 0) { Debugger.Break(); } pos = newWire.EndPos; Added.Add(newWire); Console.WriteLine($"Split wire at {split}. Result: ({newWire})"); } // Here we need to add the last part of the wire Wire w = new Wire(pos, (mergedWire.EndPos - pos).ManhattanDistance, mergedWire.Direction); Added.Add(w); Console.WriteLine($"End part of split: {w}"); // FIXME: We want to deduplicate the values in Added and Deleted // If both lists contain exactly the same wires we want to return // null instead as the transaction doesn't change anything. // Remove all wires with zero length Added.RemoveAll(w => { if (w.Length == 0) { Console.WriteLine($"Warn: Trying to add a wire with zero length! {w}"); return(true); } else { return(false); } }); // Now we just return the transaction. // To apply this transaction ApplyTransaction(...) must be called. return(new WireTransaction(wire, Deleted, Added)); }