Ejemplo n.º 1
0
        public CircuitEditor()
        {
            DrawingArea = new DrawingArea();

            Offset = DisplayOffset = new Vector2d(0, 0);

            DrawingArea.Drawn += CircuitEditor_Drawn;

            DrawingArea.AddEvents((int)EventMask.PointerMotionMask);
            DrawingArea.AddEvents((int)EventMask.ScrollMask);

            DragGesture = new GestureDrag(DrawingArea);

            // Sets middle click as the pan button.
            // This should be configurable later!
            DragGesture.Button = 2;

            DragGesture.DragBegin  += DragGesture_DragBegin;
            DragGesture.DragEnd    += DragGesture_DragEnd;
            DragGesture.DragUpdate += DragGesture_DragUpdate;

            DragGestureCreate = new GestureDrag(DrawingArea);
            // Sets middle click as the wire creation button.
            // This should be configurable later!
            DragGestureCreate.Button      = 1;
            DragGestureCreate.DragBegin  += DragGestureCreate_DragBegin;
            DragGestureCreate.DragUpdate += DragGestureCreate_DragUpdate;
            DragGestureCreate.DragEnd    += DragGestureCreate_DragEnd;

            DrawingArea.MotionNotifyEvent += DrawingArea_MotionNotifyEvent;

            DrawingArea.ScrollEvent += CircuitEditor_ScrollEvent;

            DrawingArea.QueryTooltip += CircuitEditor_QueryTooltip;

            DrawingArea.HasTooltip = true;

            DrawingArea.CanFocus     = true;
            DrawingArea.FocusOnClick = true;

            DrawingArea.AddEvents((int)EventMask.KeyPressMask);
            DrawingArea.KeyPressEvent += DrawingArea_KeyPressEvent;

            // So that we can grab focus. Without focus we won't get any KeyPressEvents...
            // FIXME: We want to figure out how to do this in a good way where the user doesn't really
            // need to know where the current focus is for stuff like ctrl+z to work.
            DrawingArea.ParentSet        += DrawingArea_ParentSet;
            DrawingArea.ButtonPressEvent += DrawingArea_ButtonPressEvent;

            var wiresArr = new Wire[]
            {
                /*new Wire(new Vector2i(3, 3), 10, Direction.Vertical),
                 * new Wire(new Vector2i(3, 13), 10, Direction.Horizontal),
                 * new Wire(new Vector2i(0, 3), 3, Direction.Horizontal),
                 * new Wire(new Vector2i(3, 0), 3, Direction.Vertical),
                 * new Wire(new Vector2i(0, 13), 3, Direction.Horizontal),
                 * new Wire(new Vector2i(13, 12), -9, Direction.Vertical),
                 * new Wire(new Vector2i(4, 3), 9, Direction.Horizontal),
                 * new Wire(new Vector2i(13, 3), 4, Direction.Horizontal),*/
            };

            var gates = new Gates();

            var wires = new Wires(gates, wiresArr);

            var labels = new TextLabels(new TextLabel[]
            {
                new TextLabel(new Vector2d(0, 0), "This is some cool text.", 14),
                new TextLabel(new Vector2d(40, 10), "Even more cool text :O", 24),
                new TextLabel(new Vector2d(40, 40), "Woahhh :OOOoooO", 72),
            });

            Scene = new Scene(wires, gates, labels);
        }
Ejemplo 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));
        }
Ejemplo n.º 3
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));
        }
Ejemplo n.º 4
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));
        }
Ejemplo n.º 5
0
        public CircuitEditor()
        {
            DrawingArea = new DrawingArea();

            Offset = DisplayOffset = new Vector2d(0, 0);

            DrawingArea.Drawn += CircuitEditor_Drawn;

            DrawingArea.AddEvents((int)EventMask.PointerMotionMask);
            DrawingArea.AddEvents((int)EventMask.ScrollMask);

            DragGesture = new GestureDrag(DrawingArea);

            // Sets middle click as the pan button.
            // This should be configurable later!
            DragGesture.Button = 2;

            DragGesture.DragBegin  += DragGesture_DragBegin;
            DragGesture.DragEnd    += DragGesture_DragEnd;
            DragGesture.DragUpdate += DragGesture_DragUpdate;

            DragGestureCreate = new GestureDrag(DrawingArea);
            // Sets middle click as the wire creation button.
            // This should be configurable later!
            DragGestureCreate.Button      = 1;
            DragGestureCreate.DragBegin  += DragGestureCreate_DragBegin;
            DragGestureCreate.DragUpdate += DragGestureCreate_DragUpdate;
            DragGestureCreate.DragEnd    += DragGestureCreate_DragEnd;


            DrawingArea.ScrollEvent += CircuitEditor_ScrollEvent;

            DrawingArea.QueryTooltip += CircuitEditor_QueryTooltip;

            DrawingArea.HasTooltip = true;

            DrawingArea.CanFocus     = true;
            DrawingArea.FocusOnClick = true;

            DrawingArea.AddEvents((int)EventMask.KeyPressMask);
            DrawingArea.KeyPressEvent += DrawingArea_KeyPressEvent;

            // So that we can grab focus. Without focus we won't get any KeyPressEvents...
            // FIXME: We want to figure out how to do this in a good way where the user doesn't really
            // need to know where the current focus is for stuff like ctrl+z to work.
            DrawingArea.ParentSet        += DrawingArea_ParentSet;
            DrawingArea.ButtonPressEvent += DrawingArea_ButtonPressEvent;

            var powered = new Wire[]
            {
                new Wire(new Vector2i(3, 3), 10, Direction.Vertical),
                new Wire(new Vector2i(3, 13), 10, Direction.Horizontal),
                new Wire(new Vector2i(0, 3), 3, Direction.Horizontal),
                new Wire(new Vector2i(3, 0), 3, Direction.Vertical),
                new Wire(new Vector2i(0, 13), 3, Direction.Horizontal),
            };
            var unpowered = new Wire[]
            {
                new Wire(new Vector2i(13, 12), -9, Direction.Vertical),
                new Wire(new Vector2i(4, 3), 9, Direction.Horizontal),
                new Wire(new Vector2i(13, 3), 4, Direction.Horizontal),
            };

            Wires = new Wires(
                powered,
                unpowered,
                // For wires to connect their start/end point must be at the same location
                // A wire that start/ends in the middle of another wires doesn't connect
                // (We might want to change that but it becomes more complicated then...)
                Wires.FindConnectionPoints(powered).ToArray(),
                Wires.FindConnectionPoints(unpowered).ToArray());

            Gates = new Gates(/*new AndGate[]
                               * {
                               * new AndGate(new Vector2i(2, 2), Orientation.South),
                               * new AndGate(new Vector2i(3, 7), Orientation.East),
                               * new AndGate(new Vector2i(3, 10), Orientation.West),
                               * new AndGate(new Vector2i(5, 3), Orientation.North),
                               * }*/);

            Labels = new TextLabels(new TextLabel[]
            {
                new TextLabel(new Vector2d(0, 0), "This is some cool text.", 14),
                new TextLabel(new Vector2d(40, 10), "Even more cool text :O", 24),
                new TextLabel(new Vector2d(40, 40), "Woahhh :OOOoooO", 72),
            });
        }