public LinkViewModel(PadViewModel src, PadViewModel sink) { this.Src = src; this.Sink = sink; var srcX = src.WhenAnyValue(src => src.X); var srcY = src.WhenAnyValue(src => src.Y); var sinkX = sink.WhenAnyValue(sink => sink.X); var sinkY = sink.WhenAnyValue(sink => sink.Y); var x = srcX.CombineLatest(sinkX, Math.Min).Select(x => x - Settings.LinkBezierPadding); var y = srcY.CombineLatest(sinkY, Math.Min).Select(y => y - Settings.LinkBezierPadding); this.x = x.ToProperty(this, x => x.X); this.y = y.ToProperty(this, x => x.Y); var width = srcX.CombineLatest(sinkX, (srcX, sinkX) => Math.Max(1, Math.Abs(sinkX - srcX)) + (2 * Settings.LinkBezierPadding)); var height = srcY.CombineLatest(sinkY, (srcY, sinkY) => Math.Max(1, Math.Abs(sinkY - srcY)) + (2 * Settings.LinkBezierPadding)); this.width = width.ToProperty(this, pad => pad.Width); this.height = height.ToProperty(this, pad => pad.Height); var srcXOffset = x.CombineLatest(srcX, (x, srcX) => srcX + Settings.PadRadius - x).Where(offset => offset >= 0); var srcYOffset = y.CombineLatest(srcY, (y, srcY) => srcY + Settings.PadRadius - y).Where(offset => offset >= 0); var sinkXOffset = x.CombineLatest(sinkX, (x, sinkX) => sinkX + Settings.PadRadius - x).Where(offset => offset >= 0); var sinkYOffset = y.CombineLatest(sinkY, (y, sinkY) => sinkY + Settings.PadRadius - y).Where(offset => offset >= 0); var start = srcXOffset.CombineLatest(srcYOffset, (x, y) => new Point(x, y)); var end = sinkXOffset.CombineLatest(sinkYOffset, (x, y) => new Point(x, y)); this.start = start.ToProperty(this, pad => pad.Start); this.end = end.ToProperty(this, pad => pad.End); var control1 = start.CombineLatest(width, (start, width) => { return(start + new Vector(Math.Max(width / 2, 25), 0)); }); var control2 = end.CombineLatest(width, (end, width) => { return(end + new Vector(-Math.Max(width / 2, 25), 0)); }); this.control1 = control1.ToProperty(this, pad => pad.Control1); this.control2 = control2.ToProperty(this, pad => pad.Control2); this.WhenActivated((disposables) => { this.x.DisposeWith(disposables); this.y.DisposeWith(disposables); this.width.DisposeWith(disposables); this.height.DisposeWith(disposables); this.start.DisposeWith(disposables); this.control1.DisposeWith(disposables); this.control2.DisposeWith(disposables); this.end.DisposeWith(disposables); }); }