private void NodeControl_MouseDown(object sender, MouseButtonEventArgs e) { CaptureMouse(); scene_rendering_control.UpdateMouseTracking(e, true); if (e.LeftButton == MouseButtonState.Pressed) { scene_rendering_control.selected_connector_control.Selected = null; if ((Keyboard.Modifiers & ModifierKeys.Alt) > 0) { NodeControl nc_linked = sender as NodeControl; foreach (NodeControl node_control in scene_rendering_control.GetSelectedNodeControls()) { ConnectorControl cc = new ConnectorControl(scene_rendering_control); cc.SetNodes(node_control, nc_linked); scene_rendering_control.AddNewConnectorControl(cc); } } else { if (!scene_rendering_control.IsSelectedNodeControl(this)) { scene_rendering_control.SetSelectedNodeControl(sender as NodeControl, scene_rendering_control.IsUserIndicatingAddToSelection()); scene_rendering_control.selected_connector_control.Selected = null; } } e.Handled = true; } }
public void Add(ConnectorControl connector_control) { connector_controls.Add(connector_control); links_from_to.Add(connector_control.node_from, connector_control); links_from_to.Add(connector_control.node_to, connector_control); }
public ItemConnector(FrameworkElement parent, double width, double height) { _uiControl = new ConnectorControl(parent); _uiControl.Width = width; _uiControl.Height = height; UIElement = _uiControl; }
internal static void AddSiblingToNodeControl(NodeControl node_control) { List <ConnectorControl> connectors_both; List <ConnectorControl> connectors_to; List <ConnectorControl> connectors_from; GetAdjoiningConnectors(node_control.scene_rendering_control, node_control, out connectors_both, out connectors_to, out connectors_from); double left = node_control.scene_data.CentreX; double top = node_control.scene_data.CentreY; double width = node_control.scene_data.Width; double height = node_control.scene_data.Height; top += 1.5 * height; NodeControlSceneData scene_data = new NodeControlSceneData(); object content = new StringNodeContent("Sibling node"); NodeControl node_new = node_control.scene_rendering_control.AddNewNodeControl(content, left, top, width, height); if (connectors_to.Count > 0) { NodeControl node_control_parent = connectors_to[connectors_to.Count - 1].node_from; ConnectorControl connector_new = new ConnectorControl(node_control.scene_rendering_control); connector_new.SetNodes(node_control_parent, node_new); node_control.scene_rendering_control.AddNewConnectorControl(connector_new); } node_control.scene_rendering_control.SetSelectedNodeControl(node_new, false); }
void SelectedConnector_OnDimensionsChanged(ConnectorControl cc) { double SPACER = 4; this.Width = cc.Width + SPACER + SPACER; this.Height = cc.Height + SPACER + SPACER; Canvas.SetLeft(this, Canvas.GetLeft(cc) - SPACER); Canvas.SetTop(this, Canvas.GetTop(cc) - SPACER); Canvas.SetZIndex(this, Canvas.GetZIndex(cc) + 1); }
private static void CreateSampleScene(SceneRenderingControl scene_rendering_control, double x, double y, double skew) { int N = 300; Random random = new Random(); string[] icon_filenames = new string[] { "papers/binoculars", "papers/boat", "papers/flame", "papers/radioactive", "papers/bread", "papers/news", "papers/music", "papers/percentage", "papers/postit" }; NodeControl[] ncs = new NodeControl[N]; for (int i = 0; i < N; ++i) { object node_content; switch (i % 2) { case 0: { IconNodeContent icon_node_content = new IconNodeContent(icon_filenames[random.Next(icon_filenames.Length)]); node_content = icon_node_content; break; } case 1: { StringNodeContent snc = new StringNodeContent(); snc.Text = String.Format("Button {0}", i); node_content = snc; break; } default: node_content = null; break; } double raw_angle = 6 * i * Math.PI / 100; double distance = 10 + i * 4 + RandomAugmented.Instance.NextDouble() * 10; double left = x + distance * (-2 + skew) * Math.Sin(raw_angle) + RandomAugmented.Instance.NextDouble() * 30 - 15; double top = y + distance * (+2 + skew) * Math.Cos(raw_angle) + RandomAugmented.Instance.NextDouble() * 30 - 15; ncs[i] = scene_rendering_control.AddNewNodeControl(node_content, left, top); // A line for this to the prev nc if (i > 3 && (i / 2) % 20 == 0) { for (int j = 0; j < 3; ++j) { ConnectorControl cc = new ConnectorControl(scene_rendering_control); cc.SetNodes(ncs[i - j], ncs[i]); scene_rendering_control.AddNewConnectorControl(cc); } } } }
private void AddNewConnector(object sender, RoutedEventArgs e) { var tempConnector = new ConnectorControl() { PositionOnElement = Position.center, ManipulationMode = ManipulationModes.TranslateX | ManipulationModes.TranslateY }; cWorkSpace.Children.Add(tempConnector); tempConnector.AddMenuFlyout(); Canvas.SetLeft(tempConnector, CursorPosition.X); Canvas.SetTop(tempConnector, CursorPosition.Y); }
private void DoLayout() { int SPEED = 1; // If the nodes and connectors have changed, recache them! if (cache_scene_changed_timestamp != this.scene_rendering_control.SceneChangedTimestamp) { Logging.Info("Scene has changed, so autolayout is recaching."); cache_scene_changed_timestamp = this.scene_rendering_control.SceneChangedTimestamp; cache_node_controls = new List <NodeControl>(this.scene_rendering_control.NodeControls); cache_connector_controls = new List <ConnectorControl>(this.scene_rendering_control.ConnectorControlManager.ConnectorControls); } // We reuse this so that it is memory allocation time efficient NodesVector vector = new NodesVector(); // Perform the attraction if (true) { int MAX_CONNECTORS = cache_connector_controls.Count; for (int i = 0; i < MAX_CONNECTORS; ++i) { ConnectorControl connector = cache_connector_controls[i]; if (connector.Deleted) { continue; } NodeControlSceneData nodeI = connector.NodeFrom.NodeControlSceneData; NodeControlSceneData nodeJ = connector.NodeTo.NodeControlSceneData; vector.Recalculate(nodeI, nodeJ); double strength = -1 * SPEED * (vector.distance / vector.minimum_extent); DoPushPull(nodeI, nodeJ, vector, strength); } } // Perform the repulsion if (true) { int MAX_NODES = cache_node_controls.Count; for (int i = 0; i < MAX_NODES; ++i) { NodeControlSceneData nodeI = cache_node_controls[i].NodeControlSceneData; if (nodeI.Deleted) { continue; } for (int j = i + 1; j < MAX_NODES; ++j) { NodeControlSceneData nodeJ = cache_node_controls[j].NodeControlSceneData; if (nodeJ.Deleted) { continue; } vector.Recalculate(nodeI, nodeJ); double strength = SPEED * Math.Min(2, (vector.minimum_extent / (vector.box_distance + 1))); DoPushPull(nodeI, nodeJ, vector, strength); } } } NotifySceneRenderingControl(); }
void SelectedConnector_OnDeleted(ConnectorControl cc) { this.Selected = null; }
private void DoLayout() { int SPEED = 1; // If the nodes and connectors have changed, recache them! if (cache_scene_changed_timestamp != scene_rendering_control.SceneChangedTimestamp) { Logging.Info("Scene has changed, so autolayout is recaching."); cache_scene_changed_timestamp = scene_rendering_control.SceneChangedTimestamp; cache_node_controls = new List <NodeControl>(scene_rendering_control.NodeControls); cache_connector_controls = new List <ConnectorControl>(scene_rendering_control.ConnectorControlManager.ConnectorControls); } // We reuse this so that it is memory allocation time efficient NodesVector vector = new NodesVector(); // Also note that Utilities codebase had ATTRACTION *before* REPULSION. // Haven't looked at the precise code, but wouldn't be surprised if this is // very similar to the D3 force anneal code (D3.js) anyway. There aren't that // many ways to stabilize a (large) graph in 2D. // // See also https://github.com/jimmejardine/qiqqa-open-source/issues/26 // Perform the repulsion if (true) { int MAX_NODES = cache_node_controls.Count; for (int i = 0; i < MAX_NODES; ++i) { NodeControlSceneData nodeI = cache_node_controls[i].NodeControlSceneData; if (nodeI.Deleted) { continue; } for (int j = i + 1; j < MAX_NODES; ++j) { NodeControlSceneData nodeJ = cache_node_controls[j].NodeControlSceneData; if (nodeJ.Deleted) { continue; } vector.Recalculate(nodeI, nodeJ); // Utilities code had: // // See also https://github.com/jimmejardine/qiqqa-open-source/issues/26 #if UNUSED_CODE double strength = SPEED * Math.Min(2, (vector.minimum_extent / (vector.box_distance + 1))); DoPushPull(nodeI, nodeJ, vector, strength); #else // Qiqqa code chunk alt: double strength = vector.maximum_extent * SPEED * (1 / (vector.box_distance + 1)); strength = Math.Min(strength, 5); if (strength > 10) { } // end of Qiqqa alt chunk; looks to me like someone has been fiddling around here... // (including the logline below, which was also not in Utilities codebase... DoPushPull(nodeI, nodeJ, vector, strength); //Logging.Info("REPULSE STRENGTH={0}, box.distance={1}", strength, vector.box_distance); #endif } } } // Perform the attraction if (true) { int MAX_CONNECTORS = cache_connector_controls.Count; for (int i = 0; i < MAX_CONNECTORS; ++i) { ConnectorControl connector = cache_connector_controls[i]; if (connector.Deleted) { continue; } NodeControlSceneData nodeI = connector.NodeFrom.NodeControlSceneData; NodeControlSceneData nodeJ = connector.NodeTo.NodeControlSceneData; vector.Recalculate(nodeI, nodeJ); #if UNUSED_CODE // Utilities codebase was: // See also https://github.com/jimmejardine/qiqqa-open-source/issues/26 double strength = -1 * SPEED * (vector.distance / vector.minimum_extent); DoPushPull(nodeI, nodeJ, vector, strength); #else double strength = -1 * SPEED * (vector.box_distance / 50); DoPushPull(nodeI, nodeJ, vector, strength); //Logging.Info("ATTRACT STRENGTH={0}", strength); #endif } } NotifySceneRenderingControl(); }
public static void CreateSampleScene_Coordinates(SceneRenderingControl scene_rendering_control) { int EXTENT = 30; int SCALE = 100; NodeControl nx = scene_rendering_control.AddNewNodeControl(new StringNodeContent() { Text = "nx" }, -2 * SCALE * EXTENT, 0, 100, 100); NodeControl px = scene_rendering_control.AddNewNodeControl(new StringNodeContent() { Text = "px" }, +2 * SCALE * EXTENT, 0, 100, 100); NodeControl ny = scene_rendering_control.AddNewNodeControl(new StringNodeContent() { Text = "ny" }, 0, -2 * SCALE * EXTENT, 100, 100); NodeControl py = scene_rendering_control.AddNewNodeControl(new StringNodeContent() { Text = "py" }, 0, +2 * SCALE * EXTENT, 100, 100); for (int x = -EXTENT; x <= EXTENT; ++x) { for (int y = -EXTENT; y <= EXTENT; ++y) { double width = 100 / (1 + Math.Abs(x) + Math.Abs(y)); double height = 100 / (1 + Math.Abs(x) + Math.Abs(y)); double xpos = x * SCALE; double ypos = y * SCALE; StringNodeContent snc = new StringNodeContent(); snc.Text = String.Format("{0} {1}", xpos, ypos); NodeControl node_control = scene_rendering_control.AddNewNodeControl(snc, xpos, ypos, width, height); if (x == -EXTENT) { ConnectorControl cc = new ConnectorControl(scene_rendering_control); cc.SetNodes(nx, node_control); scene_rendering_control.AddNewConnectorControl(cc); } if (x == +EXTENT) { ConnectorControl cc = new ConnectorControl(scene_rendering_control); cc.SetNodes(px, node_control); scene_rendering_control.AddNewConnectorControl(cc); } if (y == -EXTENT) { ConnectorControl cc = new ConnectorControl(scene_rendering_control); cc.SetNodes(ny, node_control); scene_rendering_control.AddNewConnectorControl(cc); } if (y == +EXTENT) { ConnectorControl cc = new ConnectorControl(scene_rendering_control); cc.SetNodes(py, node_control); scene_rendering_control.AddNewConnectorControl(cc); } } } }
public static void AddChildToNodeControl(NodeControl node_control_parent, object content, bool select_node) { List <ConnectorControl> connectors_both; List <ConnectorControl> connectors_to; List <ConnectorControl> connectors_from; GetAdjoiningConnectors(node_control_parent.scene_rendering_control, node_control_parent, out connectors_both, out connectors_to, out connectors_from); // Get the average connectors direction Point direction_inbound = new Point(0, 0); int denominator = 0; foreach (ConnectorControl connector in connectors_to) { if (connector.Deleted) { continue; } direction_inbound.X += connector.node_to.NodeControlSceneData.CentreX - connector.node_from.NodeControlSceneData.CentreX; direction_inbound.Y += connector.node_to.NodeControlSceneData.CentreY - connector.node_from.NodeControlSceneData.CentreY; denominator += 1; } if (0 < denominator) { direction_inbound.X /= denominator; direction_inbound.Y /= denominator; } else { double angle = Math.PI * 140.0 / 180.0 * (1 + connectors_from.Count); double max_dimension = Math.Max(node_control_parent.scene_data.Width, node_control_parent.scene_data.Height); direction_inbound.X = 1.5 * max_dimension * Math.Cos(angle); direction_inbound.Y = 1.5 * max_dimension * Math.Sin(angle); } // Pick an outward direction Point direction_outbound = new Point(direction_inbound.X, direction_inbound.Y); double total_divergence = 0.0; if (connectors_to.Count > 0) { double current_divergence = Math.PI / 4; int i = connectors_from.Count; while (i > 0) { int remainder = i % 2; if (remainder > 0) { total_divergence += current_divergence; } else { total_divergence -= current_divergence; } current_divergence = current_divergence / 2; i = i / 2; } } // Rotate the direction Point direction_outbound_rotated = new Point(); direction_outbound_rotated.X = direction_outbound.X * Math.Cos(total_divergence) + direction_outbound.Y * Math.Sin(total_divergence); direction_outbound_rotated.Y = -direction_outbound.X * Math.Sin(total_divergence) + direction_outbound.Y * Math.Cos(total_divergence); double CHILD_SHRINKAGE_FACTOR = 0.8; double left = node_control_parent.scene_data.CentreX + direction_outbound_rotated.X * CHILD_SHRINKAGE_FACTOR; double top = node_control_parent.scene_data.CentreY + direction_outbound_rotated.Y * CHILD_SHRINKAGE_FACTOR; //xxxxxxxxxxxxxxxxxxxxxxxxx double width = node_control_parent.scene_data.Width * CHILD_SHRINKAGE_FACTOR; double height = node_control_parent.scene_data.Height * CHILD_SHRINKAGE_FACTOR; // Create a node at the outbound direction NodeControl node_new = node_control_parent.scene_rendering_control.AddNewNodeControl(content, left, top, width, height); if (node_new != node_control_parent) { // Check that we are not connected to the node control if it is being reused bool already_connected = false; if (!already_connected) { foreach (ConnectorControl cc in connectors_to) { if (cc.node_from == node_new) { already_connected = true; break; } } } if (!already_connected) { foreach (ConnectorControl cc in connectors_from) { if (cc.node_to == node_new) { already_connected = true; break; } } } // Create a link to the new child if (!already_connected) { ConnectorControl connector_new = new ConnectorControl(node_control_parent.scene_rendering_control); connector_new.SetNodes(node_control_parent, node_new); node_control_parent.scene_rendering_control.AddNewConnectorControl(connector_new); } // Choose this new node if (select_node) { node_control_parent.scene_rendering_control.SetSelectedNodeControl(node_new, false); } } }