/// <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> /// Get the closest endpoint from this shape to the given shape. /// </summary> /// <param name="othershape">The shape to compare to</param> /// <returns>The closest endpoint in otherShape</returns> public EndPoint ClosestEndpointTo(Shape othershape) { return(othershape.ClosestEndpointFrom(this)); }
/// <summary> /// Connects the given shape to the other shapes in the sketch. /// /// Postcondition: /// If the shape is a wire, the following things are true: /// - For every substroke in the wire, both endpoints are connected to the closest shape /// - The shapes the endpoints are connected to are also in the list of connected shapes /// - The shapes that the wire is connected to also know they are connected to the wire /// If the shape is a NOTBUBBLE /// - It is connected to the two closest shapes?? /// </summary> /// <param name="shape">The shape to check.</param> /// <param name="sketch">The sketch containing the shape.</param> public override void ConnectShape(Sketch.Shape shape, Sketch.Sketch sketch) { if (!sketch.ShapesL.Contains(shape)) { throw new ArgumentException("The given shape " + shape + " is not in the given sketch!"); } // Connect wires to adjacent shapes if (shape.Type == LogicDomain.WIRE) { foreach (Sketch.Substroke substroke in shape.Substrokes) { // Find the shape closest to the start point of the wire Shape shape2 = findClosest(true, substroke, sketch); if (shape2 != null) { EndPoint start = substroke.Endpoints[0]; if (!start.IsConnected) { sketch.connectShapes(shape, shape2); start.ConnectedShape = shape2; } } // Find the shape closest to the end point of the wire Shape shape3 = findClosest(false, substroke, sketch); if (shape3 != null) { EndPoint end = substroke.Endpoints[1]; if (!end.IsConnected) { sketch.connectShapes(shape, shape3); end.ConnectedShape = shape3; } } } } // Connect NotBubbles to its two closest shapes. // FIXME: This could potentially cause problems. For instance, // on the off chance that one of the closest shapes was a wire // whose connections were already figured out, this could leave // the wire in an inconsistent state. else if (shape.Type == LogicDomain.NOTBUBBLE) { List <Sketch.Shape> shapes = twoClosest(shape, sketch); foreach (Shape closeShape in shapes) { if (closeShape == null) { continue; } // FIXME: For now, we're only connecting this notbubble to a wire if that wire's closest endpoint is free. if (closeShape.Type == LogicDomain.WIRE) { EndPoint endpoint = shape.ClosestEndpointFrom(closeShape); if (!endpoint.IsConnected) { closeShape.ConnectNearestEndpointTo(shape); } } else { sketch.connectShapes(closeShape, shape); } } } }