Exemplo n.º 1
0
        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));
        }
Exemplo n.º 2
0
        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));
        }
Exemplo n.º 3
0
        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));
        }
Exemplo n.º 4
0
        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));
        }