private void d2dControl_DrawingD2d(object sender, EventArgs e) { // if we're dragging, or could drag and no one else is dragging... if (Dragging() || (DragPossible() && !AdaptedControl.Capture)) { var d2dControl = this.AdaptedControl as D2dAdaptableControl; D2dGraphics gfx = d2dControl.D2dGraphics; Rectangle frameRect = GetItemBounds(); if (!frameRect.IsEmpty) { Matrix transform = m_transformAdapter.Transform; frameRect = GdiUtil.Transform(transform, frameRect); frameRect.Inflate(-HandleSize, -HandleSize); gfx.Transform = Matrix3x2F.Identity; gfx.FillRectangle(GetHandleRect(frameRect, Direction.TopLeft), Color.Gray); gfx.FillRectangle(GetHandleRect(frameRect, Direction.Top), Color.Gray); gfx.FillRectangle(GetHandleRect(frameRect, Direction.TopRight), Color.Gray); gfx.FillRectangle(GetHandleRect(frameRect, Direction.Right), Color.Gray); gfx.FillRectangle(GetHandleRect(frameRect, Direction.BottomRight), Color.Gray); gfx.FillRectangle(GetHandleRect(frameRect, Direction.Bottom), Color.Gray); gfx.FillRectangle(GetHandleRect(frameRect, Direction.BottomLeft), Color.Gray); gfx.FillRectangle(GetHandleRect(frameRect, Direction.Left), Color.Gray); gfx.Transform = transform; } } }
/// <summary> /// Draws the scale manipulator and calculates the bounding rectangles on the left and right /// handles</summary> /// <param name="g">The graphics object to draw with</param> /// <param name="leftHandle">The left handle's bounding rectangle for pick tests, in view /// coordinates</param> /// <param name="rightHandle">The right handle's bounding rectangle for pick tests, in view /// coordinates</param> protected virtual void DrawManipulator(D2dGraphics g, out RectangleF leftHandle, out RectangleF rightHandle) { const float penWidth = 3; Matrix worldToView = Owner.Transform; float viewMin = GdiUtil.Transform(worldToView, WorldMin); float viewMax = GdiUtil.Transform(worldToView, WorldMax); leftHandle = new RectangleF(viewMin - penWidth * 0.5f, 0.0f, penWidth, HandleHeight); rightHandle = new RectangleF(viewMax - penWidth * 0.5f, 0.0f, penWidth, HandleHeight); if (IsScaling && ScaleHelper.Mode == ScaleMode.TimePeriod) { // Draw lines in red at current ghost position. viewMin = GdiUtil.Transform(worldToView, ScaleHelper.WorldGhostMin); viewMax = GdiUtil.Transform(worldToView, ScaleHelper.WorldGhostMax); g.DrawLine(viewMin, 0.0f, viewMax, 0.0f, Color.Red, penWidth, null); g.DrawLine(viewMin, 0.0f, viewMin, HandleHeight, Color.Red, penWidth, null); g.DrawLine(viewMax, 0.0f, viewMax, HandleHeight, Color.Red, penWidth, null); } else { // Draw using original positions and the usual color. g.DrawLine(viewMin, 0.0f, viewMax, 0.0f, Color, penWidth, null); g.DrawLine(viewMin, 0.0f, viewMin, HandleHeight, Color, penWidth, null); g.DrawLine(viewMax, 0.0f, viewMax, HandleHeight, Color, penWidth, null); } }
/// <summary> /// Gets the bounding rect of an edge, in graph space (world space)</summary> /// <param name="edge">Edge</param> /// <param name="g">D2dGraphics object</param> /// <returns>Rectangle completely bounding the node in graph space</returns> public virtual RectangleF GetBounds(TEdge edge, D2dGraphics g) { RectangleF bounds = GetBounds(edge.FromNode, g); bounds = RectangleF.Union(bounds, GetBounds(edge.ToNode, g)); return(bounds); }
/// <summary> /// Draws grid lines corresponding to a vertical scale</summary> /// <param name="g">The Direct2D graphics object</param> /// <param name="transform">Graph (world) to window's client (screen) transform</param> /// <param name="graphRect">Graph rectangle</param> /// <param name="majorSpacing">Scale's major spacing</param> /// <param name="lineBrush">Grid line brush</param> public static void DrawVerticalScaleGrid( this D2dGraphics g, Matrix transform, RectangleF graphRect, int majorSpacing, D2dBrush lineBrush) { double xScale = transform.Elements[0]; RectangleF clientRect = Transform(transform, graphRect); double min = Math.Min(graphRect.Left, graphRect.Right); double max = Math.Max(graphRect.Left, graphRect.Right); double tickAnchor = CalculateTickAnchor(min, max); double step = CalculateStep(min, max, Math.Abs(clientRect.Right - clientRect.Left), majorSpacing, 0.0); if (step > 0) { double offset = tickAnchor - min; offset = offset - MathUtil.Remainder(offset, step) + step; for (double x = tickAnchor - offset; x <= max; x += step) { double cx = (x - graphRect.Left) * xScale + clientRect.Left; g.DrawLine((float)cx, clientRect.Top, (float)cx, clientRect.Bottom, lineBrush); } } }
private void control_DrawingD2d(object sender, EventArgs e) { if (Selector.IsSelecting) { var d2dControl = (D2dAdaptableControl)sender; D2dGraphics g = d2dControl.D2dGraphics; // Replace transform and anti-aliasing setting. Matrix3x2F xform = d2dControl.D2dGraphics.Transform; d2dControl.D2dGraphics.Transform = Matrix3x2F.Identity; D2dAntialiasMode oldAA = d2dControl.D2dGraphics.AntialiasMode; d2dControl.D2dGraphics.AntialiasMode = D2dAntialiasMode.Aliased; // Draw the selection rectangle. Rectangle rect = MakeSelectionRect( ClientToCanvas(Selector.CurrentPoint), ClientToCanvas(Selector.FirstPoint)); rect.Intersect(AdaptedControl.ClientRectangle); var rectF = new RectangleF(rect.X, rect.Y, rect.Width, rect.Height); g.DrawRectangle(rectF, SelectionBorderColor, 1.0f, null); g.FillRectangle(rectF, SelectionFillColor); // Restore D2dGraphics settings. d2dControl.D2dGraphics.Transform = xform; d2dControl.D2dGraphics.AntialiasMode = oldAA; } }
/// <summary> /// DrawingD2d event handler</summary> /// <param name="sender">Adaptable control</param> /// <param name="e">Event args</param> protected virtual void control_Paint(object sender, EventArgs e) { if (!m_isConnecting) { return; } var d2dControl = this.AdaptedControl as D2dAdaptableControl; D2dGraphics gfx = d2dControl.D2dGraphics; string label = m_draggingContext.ExistingEdge != null ? m_draggingContext.ExistingEdge.Label : null; TNode dragFromNode = m_draggingContext.ActualFromNode(); TEdgeRoute dragFromRoute = m_draggingContext.ActualFromRoute(dragFromNode); TNode dragToNode = m_draggingContext.ActualToNode(); TEdgeRoute dragToRoute = m_draggingContext.ActualToRoute(dragToNode); Debug.Assert(dragFromRoute != null || dragToRoute != null); PointF start = dragFromRoute == null ? m_edgeDragPoint : m_draggingContext.FromRoutePos; PointF end = dragToRoute == null ? m_edgeDragPoint : m_draggingContext.ToRoutePos; m_renderer.DrawPartialEdge(dragFromNode, dragFromRoute, dragToNode, dragToRoute, label, start, end, gfx); }
private Rectangle GetLabelBounds(TEdge edge, D2dGraphics g) { Vec2F startPoint = new Vec2F(); Vec2F endPoint = new Vec2F(); CircleF c = new CircleF(); bool moreThan180 = false; Vec2F textPoint; if (GetEdgeGeometry(edge, edge.FromRoute.Index, ref startPoint, ref endPoint, ref c, ref moreThan180)) { textPoint = (endPoint + startPoint) * 0.5f; } else { textPoint = (endPoint + startPoint) * 0.5f; CircleF.Project(textPoint, c, ref textPoint); if (moreThan180) { textPoint -= 2 * (textPoint - c.Center); } } float height = m_theme.TextFormat.FontHeight; float width = 32; if (!string.IsNullOrEmpty(edge.Label)) { SizeF size = g.MeasureText(edge.Label, m_theme.TextFormat); width = size.Width; height = size.Height; } return(new Rectangle((int)(textPoint.X - width * 0.5f), (int)textPoint.Y, (int)width, (int)height)); }
/// <summary> /// Draws the snap-to indicator to give the user a visual cue that snapping is occurring</summary> /// <param name="sender">The TimelineControl whose Paint event is being raised</param> /// <param name="e">The paint event args</param> /// <remarks>Draws a vertical line at the snapping location</remarks> private void owner_DrawingD2d(object sender, EventArgs e) { if (m_snapInfo.Count == 0) { return; } D2dGraphics g = m_owner.D2dGraphics; Rectangle clipRectangle = m_owner.VisibleClientRectangle; try { g.PushAxisAlignedClip(clipRectangle); Matrix worldToView = m_owner.Transform; foreach (SnapOffsetInfo info in m_snapInfo) { float viewXCoord = GdiUtil.Transform(worldToView, info.SnapToPoint); g.DrawLine(viewXCoord, clipRectangle.Top, viewXCoord, clipRectangle.Bottom, s_color, 3.0f, null); } } finally { g.PopAxisAlignedClip(); } }
internal D2dBitmap(D2dGraphics owner, SharpDX.Direct2D1.Bitmap bmp) { m_nativeBitmap = bmp; m_owner = owner; m_bitmap = null; m_owner.RecreateResources += RecreateResources; m_rtNumber = owner.RenderTargetNumber; }
/// <summary> /// Draws a partially defined graph edge</summary> /// <param name="fromNode">Source node or null</param> /// <param name="fromRoute">Source route or null</param> /// <param name="toNode">Destination node or null</param> /// <param name="toRoute">Destination route or null</param> /// <param name="label">Edge label</param> /// <param name="endPoint">Endpoint to substitute for source or destination (in client coords), if either is null</param> /// <param name="g">D2dGraphics object</param> public abstract void Draw( TNode fromNode, TEdgeRoute fromRoute, TNode toNode, TEdgeRoute toRoute, string label, Point endPoint, D2dGraphics g);
/// <summary> /// Called to prepare the Direct2D graphics device for drawing, including clearing the back buffer /// render target and initializing the Transform property of the D2dGraphics instance.</summary> protected virtual void OnBeginDrawD2d() { D2dGraphics.BeginDraw(); ITransformAdapter xform = this.As <ITransformAdapter>(); D2dGraphics.Transform = xform == null ? Matrix3x2F.Identity : xform.Transform; D2dGraphics.Clear(BackColor); D2dGraphics.AntialiasMode = D2dAntialiasMode.Aliased; }
internal D2dBitmapBrush(D2dGraphics owner, D2dBitmap bitmap) : base(owner) { m_bitmap = bitmap; m_extendModeX = D2dExtendMode.Clamp; m_extendModeY = D2dExtendMode.Clamp; m_location = new PointF(1, 1); m_interpolationMode = D2dBitmapInterpolationMode.Linear; Create();//to-do: it's dangerous to call a virtual method in a constructor; derived class may not be properly initialized! }
/// <summary> /// Draws a partially defined graph edge</summary> /// <param name="fromNode">Source node or null</param> /// <param name="fromRoute">Source route or null</param> /// <param name="toNode">Destination node or null</param> /// <param name="toRoute">Destination route or null</param> /// <param name="label">Edge label</param> /// <param name="startPoint">Startpoint for source</param> /// <param name="endPoint">Endpoint for source</param> /// <param name="g">D2dGraphics object</param> public virtual void DrawPartialEdge( TNode fromNode, TEdgeRoute fromRoute, TNode toNode, TEdgeRoute toRoute, string label, PointF startPoint, PointF endPoint, D2dGraphics g) { }
/// <summary> /// Draws a partially defined graph edge</summary> /// <param name="fromNode">Source node, or null</param> /// <param name="fromRoute">Source route, or null</param> /// <param name="toNode">Destination node, or null</param> /// <param name="toRoute">Destination route, or null</param> /// <param name="label">Edge label</param> /// <param name="endPoint">Endpoint to substitute for source or destination, if either is null</param> /// <param name="g">Graphics object</param> public override void Draw( TNode fromNode, BoundaryRoute fromRoute, TNode toNode, BoundaryRoute toRoute, string label, Point endPoint, D2dGraphics g) { // put endpoint into statechart space var inverse = g.Transform; inverse.Invert(); PointF end = Matrix3x2F.TransformPoint(inverse, endPoint); PointF p1; PointF normal1; if (fromNode != null) { p1 = ParameterToPoint(fromNode.Bounds, fromRoute.Position, out normal1); } else { p1 = end; normal1 = new Point(); } PointF p4; PointF normal2; if (toNode != null) { p4 = ParameterToPoint(toNode.Bounds, toRoute.Position, out normal2); } else { p4 = end; normal2 = new Point(); } PointF p2, p3; float d = GetTransitionPoints(p1, normal1, p4, normal2, out p2, out p3); DrawEdgeSpline(p1, p2, p3, p4, d, m_theme.OutlineBrush, g); if (!string.IsNullOrEmpty(label)) { BezierCurve2F curve = new BezierCurve2F(p1, p2, p3, p4); Vec2F midpoint = curve.Evaluate(0.5f); g.DrawText(label, m_centerText, new PointF(midpoint.X, midpoint.Y), m_theme.TextBrush); } }
/// <summary> /// Draws a graph in a print friendly way</summary> /// <param name="graph">Graph to render</param> /// <param name="g">D2dGraphics device</param> public void Print(IGraph <TNode, TEdge, TEdgeRoute> graph, D2dGraphics g) { try { IsPrinting = true; Draw(graph, null, g); } finally { IsPrinting = false; } }
/// <summary> /// Draws a partially defined graph edge</summary> /// <param name="fromNode">Source node or null</param> /// <param name="fromRoute">Source route or null</param> /// <param name="toNode">Destination node or null</param> /// <param name="toRoute">Destination route or null</param> /// <param name="label">Edge label</param> /// <param name="startPoint">Start point, in client coordinates</param> /// <param name="endPoint">End point, in client coordinates</param> /// <param name="g">D2dGraphics object</param> public virtual void DrawPartialEdge( TNode fromNode, TEdgeRoute fromRoute, TNode toNode, TEdgeRoute toRoute, string label, PointF startPoint, PointF endPoint, D2dGraphics g) { // By default, use our existing abstract implementation to draw a partial edge. Draw(fromNode, fromRoute, toNode, toRoute, label, new Point((int)endPoint.X, (int)endPoint.Y), g); }
internal D2dBitmap(D2dGraphics owner, System.Drawing.Bitmap bmp) { if (bmp.PixelFormat != GdiPixelFormat.Format32bppPArgb) { throw new System.ArgumentException("pixel format must be GdiPixelFormat.Format32bppPArgb"); } m_owner = owner; m_bitmap = bmp; Create(); m_owner.RecreateResources += RecreateResources; m_rtNumber = owner.RenderTargetNumber; }
private void Draw(TNode node, D2dGraphics g) { RectangleF boundRect = node.Bounds; D2dEllipse bounds = (D2dEllipse)boundRect; D2dLinearGradientBrush brush = m_theme.FillGradientBrush; brush.StartPoint = boundRect.Location; brush.EndPoint = new PointF(boundRect.Right, boundRect.Bottom); g.FillEllipse(bounds, brush); g.DrawEllipse(bounds, m_theme.OutlineBrush); g.DrawText(node.TitleText, m_theme.TextFormat, boundRect, m_theme.TextBrush); }
/// <summary> /// Draws a graph node</summary> /// <param name="element">Element to draw</param> /// <param name="style">Diagram drawing style</param> /// <param name="g">Graphics object</param> public override void Draw(ScriptNode element, DiagramDrawingStyle style, D2dGraphics g) { // Use the "disabled" theme when drawing disabled circuit elements. if (!((ScriptNodeElementInfo)element.ElementInfo).Enabled) { D2dDiagramTheme defaultTheme = Theme; Theme = m_disabledTheme; base.Draw(element, style, g); Theme = defaultTheme; return; } base.Draw(element, style, g); }
private void DrawArrow(D2dGraphics g, D2dBrush brush, PointF p, float dx, float dy) { const float cos = 0.866f; const float sin = 0.500f; PointF end1 = new PointF( (float)(p.X + (dx * cos + dy * -sin)), (float)(p.Y + (dx * sin + dy * cos))); PointF end2 = new PointF( (float)(p.X + (dx * cos + dy * sin)), (float)(p.Y + (dx * -sin + dy * cos))); g.DrawLine(p, end1, brush, m_theme.StrokeWidth); g.DrawLine(p, end2, brush, m_theme.StrokeWidth); }
private void DrawGhost(TNode state, D2dGraphics g) { RectangleF bounds = state.Bounds; if (state.Type != StateType.Normal) { g.FillEllipse((D2dEllipse)bounds, m_theme.GhostBrush); } else { m_stateRect.Rect = bounds; g.FillRoundedRectangle(m_stateRect, m_theme.GhostBrush); } }
/// <summary> /// Initializes class with graphics object</summary> /// <param name="graphics">Graphics object for drawing</param> public override void Init(D2dGraphics graphics) { base.Init(graphics); SelectedBrush = graphics.CreateSolidBrush(Color.Tomato);//should have width of 3 CollapsedBrush = graphics.CreateSolidBrush(Color.LightGray); InvalidBrush = graphics.CreateSolidBrush(Color.DimGray); GroupBrush = graphics.CreateLinearGradientBrush( new D2dGradientStop(Color.LightGoldenrodYellow, 0), new D2dGradientStop(Color.Khaki, 1)); GhostGroupBrush = graphics.CreateSolidBrush(Color.FromArgb(128, Color.Gray)); TrackBrush = graphics.CreateSolidBrush(Color.LightGray); GhostTrackBrush = graphics.CreateSolidBrush(Color.FromArgb(128, Color.Gray)); TextBrush = graphics.CreateSolidBrush(SystemColors.WindowText); }
internal D2dRadialGradientBrush(D2dGraphics owner, PointF center, PointF gradientOriginOffset, float radiusX, float radiusY, params D2dGradientStop[] gradientStops) : base(owner) { m_center = center; m_gradientOriginOffset = gradientOriginOffset; m_radiusX = radiusX; m_radiusY = radiusY; m_gradientStops = new D2dGradientStop[gradientStops.Length]; Array.Copy(gradientStops, m_gradientStops, m_gradientStops.Length); Create();//to-do: it's dangerous to call a virtual method in a constructor; derived class may not be properly initialized! }
/// <summary> /// Draws an icon that indicates a linked (referenced) item</summary> /// <param name="g">The Direct2D graphics object</param> /// <param name="x">X coordinate of icon top left corner</param> /// <param name="y">Y coordinate of icon top left corner</param> /// <param name="size">Size of expander, in pixels</param> /// <param name="brush">Brush</param> public static void DrawLink(this D2dGraphics g, float x, float y, float size, D2dBrush brush) { var path = new EdgeStyleData[5]; var pathData = new PointF[16]; for (int i = 0; i < 16; ++i) { pathData[i] = new PointF(s_unitCurvedArrowData[i].X * size + x, s_unitCurvedArrowData[i].Y * size + y); } var edgeData = new EdgeStyleData { ShapeType = EdgeStyleData.EdgeShape.Line, EdgeData = new PointF[] { pathData[0], pathData[1], pathData[2], pathData[3] } }; path[0] = edgeData; edgeData = new EdgeStyleData { ShapeType = EdgeStyleData.EdgeShape.Bezier, EdgeData = new BezierCurve2F(pathData[3], pathData[4], pathData[5], pathData[6]) }; path[1] = edgeData; edgeData = new EdgeStyleData { ShapeType = EdgeStyleData.EdgeShape.Bezier, EdgeData = new BezierCurve2F(pathData[6], pathData[7], pathData[8], pathData[9]) }; path[2] = edgeData; edgeData = new EdgeStyleData { ShapeType = EdgeStyleData.EdgeShape.Bezier, EdgeData = new BezierCurve2F(pathData[9], pathData[10], pathData[11], pathData[12]) }; path[3] = edgeData; edgeData = new EdgeStyleData { ShapeType = EdgeStyleData.EdgeShape.Bezier, EdgeData = new BezierCurve2F(pathData[12], pathData[13], pathData[14], pathData[15]) }; path[4] = edgeData; g.FillPath(path, brush); }
internal D2dLinearGradientBrush(D2dGraphics owner, PointF pt1, PointF pt2, D2dGradientStop[] gradientStops, D2dExtendMode extendMode, D2dGamma gamma) : base(owner) { m_start = pt1; m_end = pt2; m_gradientStops = new D2dGradientStop[gradientStops.Length]; Array.Copy(gradientStops, m_gradientStops, m_gradientStops.Length); m_gamma = gamma; m_extendMode = extendMode; Create();//to-do: it's dangerous to call a virtual method in a constructor; derived class may not be properly initialized! }
/// <summary> /// Draws a tree-control style expander, which looks like a square with /// a dash (expanded) or a cross (unexpanded)</summary> /// <param name="g">The Direct2D graphics object</param> /// <param name="x">X coordinate of expander top left corner</param> /// <param name="y">Y coordinate of expander top left corner</param> /// <param name="size">Size of expander, in pixels</param> /// <param name="brush">Brush</param> /// <param name="expanded">Whether or not expander should appear "expanded"</param> public static void DrawExpander(this D2dGraphics g, float x, float y, float size, D2dBrush brush, bool expanded) { s_expanderPoints[0] = new PointF(x, y + size); if (expanded) { s_expanderPoints[1] = new PointF(x + size, y + size); s_expanderPoints[2] = new PointF(x + size, y); g.FillPolygon(s_expanderPoints, brush); } else { s_expanderPoints[1] = new PointF(x + size, y + size / 2); s_expanderPoints[2] = new PointF(x, y); g.DrawPolygon(s_expanderPoints, brush, 1.0f); } }
internal D2dBitmap(D2dGraphics owner, int width, int height) { if (width < 1 || height < 1) { throw new ArgumentOutOfRangeException("Width and height must be greater than zero"); } m_owner = owner; var props = new SharpDX.Direct2D1.BitmapProperties(); props.DpiX = m_owner.DotsPerInch.Width; props.DpiY = m_owner.DotsPerInch.Height; props.PixelFormat = new SharpDX.Direct2D1.PixelFormat(SharpDX.DXGI.Format.B8G8R8A8_UNorm, SharpDX.Direct2D1.AlphaMode.Premultiplied); m_nativeBitmap = new SharpDX.Direct2D1.Bitmap(m_owner.D2dRenderTarget, new Size2(width, height), props); m_owner.RecreateResources += RecreateResources; m_rtNumber = owner.RenderTargetNumber; }
private void owner_DrawingD2d(object sender, EventArgs e) { // Tighten clipping region. The TimelineRenderer assumes that it has to shrink the current // Graphics.Clip region by the header width. D2dGraphics g = Owner.D2dGraphics; Rectangle clipRectangle = Owner.VisibleClientRectangle; try { g.PushAxisAlignedClip(clipRectangle); DrawManipulator(g, out m_handleRect); } finally { g.PopAxisAlignedClip(); } }
private void owner_DrawingD2d(object sender, EventArgs e) { // Test if anything is visible. m_visibleManipulator = D2dTimelineControl.CalculateRange(Owner.EditableSelection, out m_worldMin, out m_worldMax); if (!m_visibleManipulator) { return; } D2dGraphics g = Owner.D2dGraphics; Matrix worldToView = Owner.Transform; // Make the TimelineRenderer draw the ghosts, if necessary. Must happen before // the manipulator is drawn so that snap-to info is created. if (IsScaling) { TimelineLayout layout = Owner.GetLayout(); GhostInfo[] ghosts = m_resizer.CreateGhostInfo( layout, Owner.GetDragOffset().X, worldToView); Owner.Renderer.DrawGhosts( ghosts, DraggedSide, worldToView, Owner.ClientRectangle); } // Tighten clipping region. Has to occur after DrawGhosts because the TimelineRenderer // assumes that it has to shrink the current Graphics.Clip region by the header width. try { g.PushAxisAlignedClip(Owner.VisibleClientRectangle); // Draw the manipulator, giving client code a customization point. DrawManipulator(g, out m_leftHandle, out m_rightHandle); } finally { g.PopAxisAlignedClip(); } }
private void DrawArrow(Vec2F p, Vec2F d, D2dBrush brush, D2dGraphics g) { d.Normalize(); // draw arrowhead const double cos = -0.866; const double sin = -0.500; PointF head = new PointF(p.X, p.Y); PointF end1 = new PointF( (float)(p.X + (d.X * cos + d.Y * -sin) * m_arrowSize), (float)(p.Y + (d.X * sin + d.Y * cos) * m_arrowSize)); PointF end2 = new PointF( (float)(p.X + (d.X * cos + d.Y * sin) * m_arrowSize), (float)(p.Y + (d.X * -sin + d.Y * cos) * m_arrowSize)); g.DrawLine(head, end1, brush, m_theme.StrokeWidth); g.DrawLine(head, end2, brush, m_theme.StrokeWidth); }