protected override void DropOnto(System.Windows.Point pt) { // handle dropped "Instrument"s by adding them to the Link's LabelNode (a Group) // and by remembering the position of the label relative to a segment of the Link.Route var newlabs = this.Diagram.SelectedParts.OfType <Node>().Where(n => Labelable(n)).ToList(); if (newlabs.Count() > 0) { // see if the user is dropping onto a Link Link overlink = this.Diagram.Panel.FindElementAt <Link>(pt, Part.FindAncestor <Link>, p => ConsiderDragOver(pt, p), SearchLayers.Links); if (overlink != null) { PipeData linkdata = overlink.Data as PipeData; MyModel model = this.Diagram.Model as MyModel; if (linkdata != null && model != null) { // get link's existing label group ItemData labelgroup = model.GetLabelNodeForLink(linkdata); if (labelgroup == null) // create it if it doesn't have one already { labelgroup = new InstrumentData() { Key = "LG", IsSubGraph = true }; model.AddNode(labelgroup); // will provide unique Key for new group model.SetLinkLabelKey(linkdata, labelgroup.Key); } // add each dropped label to link's label group foreach (Node lab in newlabs) { ItemData labdata = lab.Data as ItemData; if (labdata != null) { model.SetGroupNodeKey(labdata, labelgroup.Key); } } } } // find closest segment for each label node and remember it and its offset foreach (Node lab in newlabs) { InstrumentData labdata = lab.Data as InstrumentData; if (labdata == null) { continue; } Group labcoll = lab.ContainingSubGraph; if (labcoll == null) { continue; } Link link = labcoll.LabeledLink; if (link != null) { Point labc = new Point(lab.Bounds.X + lab.Bounds.Width / 2, lab.Bounds.Y + lab.Bounds.Height / 2); var pts = link.Route.Points; if (pts.Count < 2) { continue; } int idx = link.Route.FindClosestSegment(labc); if (idx >= pts.Count - 1) { idx = pts.Count - 2; } labdata.Index = idx; Point a = pts[idx]; Point b = pts[idx + 1]; if (Math.Abs(a.Y - b.Y) < 0.1) { if (a.X < b.X) { labdata.Fraction = (labc.X <= a.X ? 0 : (labc.X >= b.X ? 1 : (labc.X - a.X) / (b.X - a.X))); labdata.Location = new Point(0, labc.Y - a.Y); } else { labdata.Fraction = (labc.X >= a.X ? 0 : (labc.X <= b.X ? 1 : (labc.X - a.X) / (b.X - a.X))); labdata.Location = new Point(0, a.Y - labc.Y); } } else { if (a.Y < b.Y) { labdata.Fraction = (labc.Y <= a.Y ? 0 : (labc.Y >= b.Y ? 1 : (labc.Y - a.Y) / (b.Y - a.Y))); labdata.Location = new Point(0, a.X - labc.X); } else { labdata.Fraction = (labc.Y >= a.Y ? 0 : (labc.Y <= b.Y ? 1 : (labc.Y - a.Y) / (b.Y - a.Y))); labdata.Location = new Point(0, labc.X - a.X); } } } } } else { // rotate dropped "Valve"s newlabs = this.Diagram.SelectedParts.OfType <Node>().Where(n => Spliceable(n)).ToList(); if (newlabs.Count() > 0) { // see if the user is dropping onto a Link Link overlink = this.Diagram.Panel.FindElementAt <Link>(pt, Part.FindAncestor <Link>, p => ConsiderDragOver(pt, p), SearchLayers.Links); MyModel model = this.Diagram.Model as MyModel; if (overlink != null && model != null) { // get the data representing a Pipe PipeData oldlinkdata = overlink.Data as PipeData; // get the Group holding Instruments for the Pipe, if any ItemData labelgroup = model.GetLabelNodeForLink(oldlinkdata); var pts = overlink.Route.Points; if (pts.Count >= 2) { // maybe rotate the Valve nodes foreach (Node lab in newlabs) { Point labc = new Point(lab.Bounds.X + lab.Bounds.Width / 2, lab.Bounds.Y + lab.Bounds.Height / 2); int idx = overlink.Route.FindClosestSegment(labc); if (idx >= pts.Count - 1) { idx = pts.Count - 2; } Point a = pts[idx]; Point b = pts[idx + 1]; // if the valve were bi-directional, this needs to be smarter? int angle = 0; if (Math.Abs(a.Y - b.Y) < 0.1) // horizontal { angle = (a.X < b.X ? 0 : 180); } else { angle = (a.Y < b.Y ? 90 : 270); } lab.RotationAngle = angle; // the StackPanel.Orientation governs the relative position of the TextBlock; // it is bound to the Node.RotationAngle using a ValveOrientationConverter } } base.DropOnto(pt); // this will splice the Valve(s) into the Link if (oldlinkdata != null) { // find one of the new Pipes PipeData newlinkdata = model.GetFromLinksForNode(newlabs.First().Data as ItemData).First(); // this is the label group holding all of the Instruments of the original Link if (labelgroup != null) { // attach the old group of Instruments to the new Pipe model.AddNode(labelgroup); model.SetLinkLabelKey(newlinkdata, labelgroup.Key); } } } } else // handle regular nodes { base.DropOnto(pt); } } }