예제 #1
0
        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);
                }
            }
        }