/// <summary> /// Creates a single EndPointPainter. /// /// Helper function. /// </summary> /// <param name="w">The endpoint to paint</param> /// <returns>A new EndPointPainter</returns> private EndPointPainter createEndpointPainter(Sketch.EndPoint endpoint) { // Create painter EndPointPainter epp = new EndPointPainter(endpoint, sketchPanel.InkCanvas); // Set painter type if (!endpoint.IsConnected) { epp.Type = EndPointPainter.EndPointType.Unconnected; } else if (Domain.LogicDomain.IsGate(endpoint.ConnectedShape.Type)) { epp.Type = EndPointPainter.EndPointType.ConnectedToSymbol; } else if (Domain.LogicDomain.IsText(endpoint.ConnectedShape.Type)) { epp.Type = EndPointPainter.EndPointType.ConnectedToLabel; } else if (Domain.LogicDomain.IsWire(endpoint.ConnectedShape.Type)) { epp.Type = EndPointPainter.EndPointType.ConnectedToWire; } else { epp.Type = EndPointPainter.EndPointType.UnknownConnection; } return(epp); }
/// <summary> /// Constructor /// </summary> public EndPoint(Sketch.EndPoint endpoint, bool isEnd) { m_Stroke = endpoint.ParentSub; m_End = isEnd; m_Pt = endpoint; m_AttachedEndpoints = new List <EndPoint>(); }
/// <summary> /// Look at a particular shape's orientation angle (relative to horizontal) /// and correct it if necessary. /// /// Note: Although the image recognizer gives an orientation angle, /// we are not using it. Originally, we did use it, then calculated a new /// orientation angle using wire slopes. The new orientation angle replaced /// the original angle unless they were close to each other. However, /// now we've commented that out and are using only the wire slopes. /// /// Actually, we do use image recognizer orientation angle, but only /// for NOT gates, since both sides of NOT gates have one wire. /// </summary> /// <param name="shape1">The shape to check.</param> /// <param name="sketch">The sketch containing the shape.</param> public override void OrientShape(Sketch.Shape shape, Sketch.Sketch sketch) { if (shape.Classification == LogicDomain.GATE_CLASS && shape.Type != LogicDomain.NOT) { // The gate's angle based on it's connected wires. double connectionsAngle = 0; double numConnectedWires = 0; // Check the slope orientation of adjacent wires foreach (Sketch.Shape connectedShape in shape.ConnectedShapes) { if (connectedShape.Type.Classification == LogicDomain.WIRE_CLASS) { Sketch.EndPoint endpoint = shape.ClosestEndpointFrom(connectedShape); double slope = endpoint.Slope; // negated since our y-axis is inverted. connectionsAngle -= Math.Atan(Math.Abs(slope)); numConnectedWires++; } } // Get the average angle connectionsAngle = connectionsAngle / numConnectedWires; //// Check if the two angles are close enough //if (Math.Abs(orientationAngle - connectionsAngle) % Math.PI < CLOSE_ENOUGH || // Math.PI % Math.Abs(orientationAngle - connectionsAngle) < CLOSE_ENOUGH) // shape.Orient = shape.Orient; // Don't change anything. //else // // Use the connections rather than the template rotation angle // shape.Orient = connectionsAngle; shape.Orientation = connectionsAngle; } }
/// <summary> /// Determine a shape's orientation based on the angles of incoming and outgoing /// wires. This method is highly reliable (numerous user studies have shown that /// users don't draw wires coming into a gate at meaningless orientations), but /// it is sometimes off by 180 degrees (by which I mean Pi, since we are working /// in radians). /// /// NOTE: Currently, this code is not used. HOWEVER, it is extremely reliable. Often /// moreso than the orientation obtained from the image recognizer. The refiner should /// be able to use this information. /// </summary> /// <param name="shape1">The shape to check.</param> /// <param name="sketch">The sketch containing the shape.</param> public override double OrientShape(Sketch.Shape shape, Sketch.Sketch sketch) { if (shape.Classification == LogicDomain.GATE_CLASS) { // The gate's angle based on its connected wires. double connectionsAngle = 0; double numConnectedWires = 0; // Check the slope orientation of adjacent wires foreach (Sketch.Shape connectedShape in shape.ConnectedShapes) { if (connectedShape.Type.Classification == LogicDomain.WIRE_CLASS) { Sketch.EndPoint endpoint = shape.ClosestEndpointFrom(connectedShape); double slope = endpoint.Slope; // negated since our y-axis is inverted (positive-y is down) connectionsAngle -= Math.Atan(Math.Abs(slope)); numConnectedWires++; } } // Get the average angle connectionsAngle = connectionsAngle / numConnectedWires; // Connections angle is currently in the range [-Pi, Pi], so add Pi return(connectionsAngle + Math.PI); } return(0); }
/// <summary> /// Figures out everything a given logic gate should be /// connected to, and connects them appropriately. /// /// Assumption: Every wire-mesh has a unique name. /// /// Note: this currently only deals with connections to wires. /// Hence, it does not make any connections for notbubbles yet. /// </summary> /// <param name="gate">The gate to connect</param> private void connectWiresTo(LogicGate gate) { // We keep track of what wire-meshes are inputs and outputs // so we can do sanity checks before actually connecting // them to the logic gate. List <Shape> inputWires = new List <Shape>(); List <Shape> outputWires = new List <Shape>(); int maxOutputs = _domain.NumberOutputs(gate.Type).Max; // Cycle through everything connected to the gate's associated // shape and categorize their connection type accordingly foreach (Sketch.Shape connectedShape in gate.Shape.ConnectedShapes) { // We'll take care of the not bubbles when they come up seprately if (connectedShape.Type == LogicDomain.NOTBUBBLE) { continue; } // If it's not a wire or a not bubble, something is wrong else if (!Domain.LogicDomain.IsWire(connectedShape.Type)) { throw new Exception("Gate " + gate + " was connected to non-wire, non-notbubble shape " + connectedShape); } Sketch.EndPoint connectingEndpoint = gate.Shape.ClosestEndpointFrom(connectedShape); if (gate.ShouldBeInput(connectingEndpoint)) { inputWires.Add(connectedShape); } else { outputWires.Add(connectedShape); } } // Make the connections. foreach (Shape wire in inputWires) { WireMesh inputWire = _wireMeshes[wire]; gate.ConnectInput(inputWire); } foreach (Shape wire in outputWires) { WireMesh outputWire = _wireMeshes[wire]; gate.ConnectOutput(outputWire); } gate.ConnectAllInputs(); gate.ConnectAllOutputs(); }
/// <summary> /// Allows the user to connect shapes by dragging a connection /// Stylus up connects the wire to the nearest target /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void InkCanvas_StylusUp(object sender, StylusEventArgs e) { if (debug) { Console.WriteLine("Endpoint stylus up recieved."); } // If no point has been clicked, return if (clickedIndex == null) { return; } EndPointPainter clickedPoint; endPointPainterMap.TryGetValue((int)clickedIndex, out clickedPoint); // Check if there are strokes close-by Sketch.EndPoint oldLocation = clickedPoint.EPoint; System.Windows.Point oldLocationPoint = new System.Windows.Point(oldLocation.X, oldLocation.Y); System.Windows.Point newLocation = e.GetPosition(sketchPanel.InkCanvas); System.Windows.Ink.Stroke attachedStroke = sketchPanel.InkSketch.GetInkStrokeBySubstroke(clickedPoint.EPoint.ParentSub); // Find the shape that the endpoint was dragged to // You can't connect a wire to itself! Shape closest = sketchPanel.Sketch.shapeAtPoint(newLocation.X, newLocation.Y, 10, clickedPoint.EPoint.ParentShape); if (closest != null && attachedStroke != null) //&& !clickedPoint.EPoint.IsConnected) { clickedPoint.Clear(); clickedPoint.PointShape = null; endPointPainterMap.Remove((int)clickedIndex); // pass the endpoint moved event to the display manager endPointMoved(oldLocation, newLocation, attachedStroke, closest); } else { clickedPoint.ResetMove(); } clickedPoint.PaintMe(); // Reset the clickedIndex and the editing mode sketchPanel.EnableDrawing(); clickedIndex = null; }
/// <summary> /// Connects not bubbles to gates and wires /// </summary> /// <param name="gate"></param> private void connectNotBubble(LogicGate bubble) { LogicGate parentGate = null; WireMesh wire = null; // Get the components this not bubble is connected to foreach (Shape connected in bubble.Shape.ConnectedShapes) { if (LogicDomain.IsGate(connected.Type) && parentGate == null) { parentGate = _logicGates[connected]; } else if (LogicDomain.IsWire(connected.Type)) { wire = _wireMeshes[connected]; } } // If this is not connected to a gate, connect it like a normal logic gate if (parentGate == null) { connectWiresTo(bubble); return; } // Is this bubble on the output or the input? Sketch.EndPoint connectingEndpoint = parentGate.Shape.ClosestEndpointFrom(bubble.Shape); bool isInput = parentGate.ShouldBeInput(connectingEndpoint); if (isInput) { wire.ConnectDependent(bubble); parentGate.ConnectInput(bubble, 0); } else { wire.ConnectSource(bubble, 0); parentGate.ConnectOutput(bubble, 0); } }