public override XPoint AddToPath(XGraphicsPath path, XPoint cursor, Base lastPathCommand = null) { if (Radii.Width == 0 || Radii.Height == 0) { path.AddLine(cursor, End.ToXPoint()); return(End.ToXPoint()); } if (End.X == cursor.X && End.Y == cursor.Y) { return(cursor); } path.AddArc(cursor, End.ToXPoint(), Radii.ToXSize(), XAxisRotation, IsLongArc, IsSweep ? XSweepDirection.Clockwise : XSweepDirection.Counterclockwise); return(End.ToXPoint()); }
private void OnAmunTextBoxSizeChanged(object sender, SizeChangedEventArgs e) { logger.I("OnAmunTextBoxSizeChanged: from " + e.PreviousSize + " to " + e.NewSize); if (!e.Handled && GridContentStreamGeoElement != null && IsUsingAmunClippingBorder) { GridContentStreamGeoElement.Clear(); Thickness borders = BorderThickness; Rect boundRect = new Rect(e.NewSize); //Rect innerRect = AIVUtil.HelperDeflateRect(boundRect, borders); using (StreamGeometryContext ctx = GridContentStreamGeoElement.Open()) { CornerRadius radii = CornerRadius; Radii innerRadii = new Radii(radii, borders, false); GenerateGeometry(ctx, boundRect, innerRadii); } } }
/// <summary> /// Generates a StreamGeometry. /// </summary> /// <param name="ctx">An already opened StreamGeometryContext.</param> /// <param name="rect">Rectangle for geomentry conversion.</param> /// <param name="radii">Corner radii.</param> /// <returns>Result geometry.</returns> private static void GenerateGeometry(StreamGeometryContext ctx, Rect rect, Radii radii) { // // compute the coordinates of the key points // Point topLeft = new Point(radii.LeftTop, 0); Point topRight = new Point(rect.Width - radii.RightTop, 0); Point rightTop = new Point(rect.Width, radii.TopRight); Point rightBottom = new Point(rect.Width, rect.Height - radii.BottomRight); Point bottomRight = new Point(rect.Width - radii.RightBottom, rect.Height); Point bottomLeft = new Point(radii.LeftBottom, rect.Height); Point leftBottom = new Point(0, rect.Height - radii.BottomLeft); Point leftTop = new Point(0, radii.TopLeft); // // check keypoints for overlap and resolve by partitioning radii according to // the percentage of each one. // // top edge is handled here if (topLeft.X > topRight.X) { double v = (radii.LeftTop) / (radii.LeftTop + radii.RightTop) * rect.Width; topLeft.X = v; topRight.X = v; } // right edge if (rightTop.Y > rightBottom.Y) { double v = (radii.TopRight) / (radii.TopRight + radii.BottomRight) * rect.Height; rightTop.Y = v; rightBottom.Y = v; } // bottom edge if (bottomRight.X < bottomLeft.X) { double v = (radii.LeftBottom) / (radii.LeftBottom + radii.RightBottom) * rect.Width; bottomRight.X = v; bottomLeft.X = v; } // left edge if (leftBottom.Y < leftTop.Y) { double v = (radii.TopLeft) / (radii.TopLeft + radii.BottomLeft) * rect.Height; leftBottom.Y = v; leftTop.Y = v; } // // add on offsets // Vector offset = new Vector(rect.TopLeft.X, rect.TopLeft.Y); topLeft += offset; topRight += offset; rightTop += offset; rightBottom += offset; bottomRight += offset; bottomLeft += offset; leftBottom += offset; leftTop += offset; // // create the border geometry // ctx.BeginFigure(topLeft, true /* is filled */, true /* is closed */); // Top line ctx.LineTo(topRight, true /* is stroked */, false /* is smooth join */); // Upper-right corner double radiusX = rect.TopRight.X - topRight.X; double radiusY = rightTop.Y - rect.TopRight.Y; if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) { ctx.ArcTo(rightTop, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false); } // Right line ctx.LineTo(rightBottom, true /* is stroked */, false /* is smooth join */); // Lower-right corner radiusX = rect.BottomRight.X - bottomRight.X; radiusY = rect.BottomRight.Y - rightBottom.Y; if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) { ctx.ArcTo(bottomRight, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false); } // Bottom line ctx.LineTo(bottomLeft, true /* is stroked */, false /* is smooth join */); // Lower-left corner radiusX = bottomLeft.X - rect.BottomLeft.X; radiusY = rect.BottomLeft.Y - leftBottom.Y; if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) { ctx.ArcTo(leftBottom, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false); } // Left line ctx.LineTo(leftTop, true /* is stroked */, false /* is smooth join */); // Upper-left corner radiusX = topLeft.X - rect.TopLeft.X; radiusY = leftTop.Y - rect.TopLeft.Y; if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) { ctx.ArcTo(topLeft, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false); } }
/// <summary> /// In addition to the child, Border renders a background + border. The background is drawn inside the border. /// </summary> protected override void OnRender(DrawingContext dc) { bool useLayoutRounding = this.UseLayoutRounding; DpiScale dpi = GetDpi(); if (_useComplexRenderCodePath) { Brush brush; StreamGeometry borderGeometry = BorderGeometryCache; if (borderGeometry != null && (brush = BorderBrush) != null) { dc.DrawGeometry(brush, null, borderGeometry); } StreamGeometry backgroundGeometry = BackgroundGeometryCache; if (backgroundGeometry != null && (brush = Background) != null) { dc.DrawGeometry(brush, null, backgroundGeometry); } } else { Thickness border = BorderThickness; Brush borderBrush; CornerRadius cornerRadius = CornerRadius; double outerCornerRadius = cornerRadius.TopLeft; // Already validated that all corners have the same radius bool roundedCorners = !DoubleUtil.IsZero(outerCornerRadius); // If we have a brush with which to draw the border, do so. // NB: We double draw corners right now. Corner handling is tricky (bevelling, &c...) and // we need a firm spec before doing "the right thing." (greglett, ffortes) if (!border.IsZero && (borderBrush = BorderBrush) != null) { // Initialize the first pen. Note that each pen is created via new() // and frozen if possible. Doing this avoids the pen // being copied when used in the DrawLine methods. Pen pen = LeftPenCache; if (pen == null) { pen = new Pen(); pen.Brush = borderBrush; if (useLayoutRounding) { pen.Thickness = UIElement.RoundLayoutValue(border.Left, dpi.DpiScaleX); } else { pen.Thickness = border.Left; } if (borderBrush.IsFrozen) { pen.Freeze(); } LeftPenCache = pen; } double halfThickness; if (border.IsUniform) { halfThickness = pen.Thickness * 0.5; // Create rect w/ border thickness, and round if applying layout rounding. Rect rect = new Rect(new Point(halfThickness, halfThickness), new Point(RenderSize.Width - halfThickness, RenderSize.Height - halfThickness)); if (roundedCorners) { dc.DrawRoundedRectangle( null, pen, rect, outerCornerRadius, outerCornerRadius); } else { dc.DrawRectangle( null, pen, rect); } } else { // Nonuniform border; stroke each edge. if (DoubleUtil.GreaterThan(border.Left, 0)) { halfThickness = pen.Thickness * 0.5; dc.DrawLine( pen, new Point(halfThickness, 0), new Point(halfThickness, RenderSize.Height)); } if (DoubleUtil.GreaterThan(border.Right, 0)) { pen = RightPenCache; if (pen == null) { pen = new Pen(); pen.Brush = borderBrush; if (useLayoutRounding) { pen.Thickness = UIElement.RoundLayoutValue(border.Right, dpi.DpiScaleX); } else { pen.Thickness = border.Right; } if (borderBrush.IsFrozen) { pen.Freeze(); } RightPenCache = pen; } halfThickness = pen.Thickness * 0.5; dc.DrawLine( pen, new Point(RenderSize.Width - halfThickness, 0), new Point(RenderSize.Width - halfThickness, RenderSize.Height)); } if (DoubleUtil.GreaterThan(border.Top, 0)) { pen = TopPenCache; if (pen == null) { pen = new Pen(); pen.Brush = borderBrush; if (useLayoutRounding) { pen.Thickness = UIElement.RoundLayoutValue(border.Top, dpi.DpiScaleY); } else { pen.Thickness = border.Top; } if (borderBrush.IsFrozen) { pen.Freeze(); } TopPenCache = pen; } halfThickness = pen.Thickness * 0.5; dc.DrawLine( pen, new Point(0, halfThickness), new Point(RenderSize.Width, halfThickness)); } if (DoubleUtil.GreaterThan(border.Bottom, 0)) { pen = BottomPenCache; if (pen == null) { pen = new Pen(); pen.Brush = borderBrush; if (useLayoutRounding) { pen.Thickness = UIElement.RoundLayoutValue(border.Bottom, dpi.DpiScaleY); } else { pen.Thickness = border.Bottom; } if (borderBrush.IsFrozen) { pen.Freeze(); } BottomPenCache = pen; } halfThickness = pen.Thickness * 0.5; dc.DrawLine( pen, new Point(0, RenderSize.Height - halfThickness), new Point(RenderSize.Width, RenderSize.Height - halfThickness)); } } } // Draw background in rectangle inside border. Brush background = Background; if (background != null) { // Intialize background Point ptTL, ptBR; if (useLayoutRounding) { ptTL = new Point(UIElement.RoundLayoutValue(border.Left, dpi.DpiScaleX), UIElement.RoundLayoutValue(border.Top, dpi.DpiScaleY)); if (FrameworkAppContextSwitches.DoNotApplyLayoutRoundingToMarginsAndBorderThickness) { ptBR = new Point(UIElement.RoundLayoutValue(RenderSize.Width - border.Right, dpi.DpiScaleX), UIElement.RoundLayoutValue(RenderSize.Height - border.Bottom, dpi.DpiScaleY)); } else { ptBR = new Point(RenderSize.Width - UIElement.RoundLayoutValue(border.Right, dpi.DpiScaleX), RenderSize.Height - UIElement.RoundLayoutValue(border.Bottom, dpi.DpiScaleY)); } } else { ptTL = new Point(border.Left, border.Top); ptBR = new Point(RenderSize.Width - border.Right, RenderSize.Height - border.Bottom); } // Do not draw background if the borders are so large that they overlap. if (ptBR.X > ptTL.X && ptBR.Y > ptTL.Y) { if (roundedCorners) { Radii innerRadii = new Radii(cornerRadius, border, false); // Determine the inner edge radius double innerCornerRadius = innerRadii.TopLeft; // Already validated that all corners have the same radius dc.DrawRoundedRectangle(background, null, new Rect(ptTL, ptBR), innerCornerRadius, innerCornerRadius); } else { dc.DrawRectangle(background, null, new Rect(ptTL, ptBR)); } } } } }
/// <summary> /// Border computes the position of its single child and applies its child's alignments to the child. /// /// </summary> /// <param name="finalSize">The size reserved for this element by the parent</param> /// <returns>The actual ink area of the element, typically the same as finalSize</returns> protected override Size ArrangeOverride(Size finalSize) { Thickness borders = BorderThickness; if (this.UseLayoutRounding && !FrameworkAppContextSwitches.DoNotApplyLayoutRoundingToMarginsAndBorderThickness) { DpiScale dpi = GetDpi(); borders = new Thickness(UIElement.RoundLayoutValue(borders.Left, dpi.DpiScaleX), UIElement.RoundLayoutValue(borders.Top, dpi.DpiScaleY), UIElement.RoundLayoutValue(borders.Right, dpi.DpiScaleX), UIElement.RoundLayoutValue(borders.Bottom, dpi.DpiScaleY)); } Rect boundRect = new Rect(finalSize); Rect innerRect = HelperDeflateRect(boundRect, borders); // arrange child UIElement child = Child; if (child != null) { Rect childRect = HelperDeflateRect(innerRect, Padding); child.Arrange(childRect); } CornerRadius radii = CornerRadius; Brush borderBrush = BorderBrush; bool uniformCorners = AreUniformCorners(radii); // decide which code path to execute. complex (geometry path based) rendering // is used if one of the following is true: // 1. there are non-uniform rounded corners _useComplexRenderCodePath = !uniformCorners; if (!_useComplexRenderCodePath && borderBrush != null) { SolidColorBrush originIndependentBrush = borderBrush as SolidColorBrush; bool uniformBorders = borders.IsUniform; _useComplexRenderCodePath = // 2. the border brush is origin dependent (the only origin independent brush is a solid color brush) (originIndependentBrush == null) // 3. the border brush is semi-transtarent solid color brush AND border thickness is not uniform // (for uniform semi-transparent border Border.OnRender draws rectangle outline - so it works fine) || ((originIndependentBrush.Color.A < 0xff) && !uniformBorders) // 4. there are rounded corners AND the border thickness is not uniform || (!DoubleUtil.IsZero(radii.TopLeft) && !uniformBorders); } if (_useComplexRenderCodePath) { Radii innerRadii = new Radii(radii, borders, false); StreamGeometry backgroundGeometry = null; // calculate border / background rendering geometry if (!DoubleUtil.IsZero(innerRect.Width) && !DoubleUtil.IsZero(innerRect.Height)) { backgroundGeometry = new StreamGeometry(); using (StreamGeometryContext ctx = backgroundGeometry.Open()) { GenerateGeometry(ctx, innerRect, innerRadii); } backgroundGeometry.Freeze(); BackgroundGeometryCache = backgroundGeometry; } else { BackgroundGeometryCache = null; } if (!DoubleUtil.IsZero(boundRect.Width) && !DoubleUtil.IsZero(boundRect.Height)) { Radii outerRadii = new Radii(radii, borders, true); StreamGeometry borderGeometry = new StreamGeometry(); using (StreamGeometryContext ctx = borderGeometry.Open()) { GenerateGeometry(ctx, boundRect, outerRadii); if (backgroundGeometry != null) { GenerateGeometry(ctx, innerRect, innerRadii); } } borderGeometry.Freeze(); BorderGeometryCache = borderGeometry; } else { BorderGeometryCache = null; } } else { BackgroundGeometryCache = null; BorderGeometryCache = null; } return(finalSize); }
/// <inheritdoc /> public override void Update(GameTime gameTime) { // In the demos, we use one time step per frame. We don't bother modifying the physics time step duration for different monitors so different refresh rates // change the rate of simulation. This doesn't actually change the result of the simulation, though, and the simplicity is a good fit for the demos. // In the context of a 'real' application, you could instead use a time accumulator to take time steps of fixed length as needed, or // fully decouple simulation and rendering rates across different threads. // (In either case, you'd also want to interpolate or extrapolate simulation results during rendering for smoothness.) // Note that taking steps of variable length can reduce stability. Gradual or one-off changes can work reasonably well. Simulation.Timestep(1 / 60f, ThreadDispatcher); Camera.Update(gameTime); if (Game.CurrentKeyboardState.IsKeyDown(Keys.Z) && CanShoot) { CanShoot = false; // Create the shape that we'll launch at the pyramids when the user presses a button. var radius = 0.5f + 5 * (float)Random.NextDouble(); var bulletShape = new Sphere(radius); // Note that the use of radius^3 for mass can produce some pretty serious mass ratios. // Observe what happens when a large ball sits on top of a few boxes with a fraction of the mass- // the collision appears much squishier and less stable. For most games, if you want to maintain rigidity, you'll want to use some combination of: // 1) Limit the ratio of heavy object masses to light object masses when those heavy objects depend on the light objects. // 2) Use a shorter timestep duration and update more frequently. // 3) Use a greater number of solver iterations. // #2 and #3 can become very expensive. In pathological cases, it can end up slower than using a quality-focused solver for the same simulation. // Unfortunately, at the moment, bepuphysics v2 does not contain any alternative solvers, so if you can't afford to brute force the the problem away, // the best solution is to cheat as much as possible to avoid the corner cases. var position = new NumericVector3(-40 + 210 * (float)Random.NextDouble(), 130, 130); var bodyDescription = BodyDescription.CreateConvexDynamic(position, new BodyVelocity(new NumericVector3((float)Random.NextDouble(), 0, -110)), bulletShape.Radius * bulletShape.Radius * bulletShape.Radius, Simulation.Shapes, bulletShape); var bodyHandle = Simulation.Bodies.Add(bodyDescription); Radii.Add(radius); SphereHandles.Add(bodyHandle); } if (Game.CurrentKeyboardState.IsKeyUp(Keys.Z)) { CanShoot = true; } BoxesWorld.Clear(); var boxHandleCount = BoxHandles.Count; for (var index = 0; index < boxHandleCount; index++) { var pose = Simulation.Bodies.GetBodyReference(BoxHandles[index]).Pose; var position = pose.Position; var quaternion = pose.Orientation; var world = Matrix.CreateFromQuaternion(new Quaternion(quaternion.X, quaternion.Y, quaternion.Z, quaternion.W)) * Matrix.CreateTranslation(new Vector3(position.X, position.Y, position.Z)); BoxesWorld.Add(world); } SpheresWorld.Clear(); var sphereHandleCount = SphereHandles.Count; for (var index = 0; index < sphereHandleCount; index++) { var pose = Simulation.Bodies.GetBodyReference(SphereHandles[index]).Pose; var position = pose.Position; var quaternion = pose.Orientation; var world = Matrix.CreateScale(Radii[index]) * Matrix.CreateFromQuaternion(new Quaternion(quaternion.X, quaternion.Y, quaternion.Z, quaternion.W)) * Matrix.CreateTranslation(new Vector3(position.X, position.Y, position.Z)); SpheresWorld.Add(world); } Game.Gizmos.UpdateViewProjection(Camera.View, Camera.Projection); base.Update(gameTime); }
/// <summary> /// In addition to the child, Border renders a background + border. The background is drawn inside the border. /// </summary> protected override void OnRender(DrawingContext dc) { bool useLayoutRounding = this.UseLayoutRounding; if (_useComplexRenderCodePath) { Brush brush; StreamGeometry borderGeometry = BorderGeometryCache; if ( borderGeometry != null && (brush = BorderBrush) != null ) { dc.DrawGeometry(brush, null, borderGeometry); } StreamGeometry backgroundGeometry = BackgroundGeometryCache; if ( backgroundGeometry != null && (brush = Background) != null ) { dc.DrawGeometry(brush, null, backgroundGeometry); } } else { Thickness border = BorderThickness; Brush borderBrush; CornerRadius cornerRadius = CornerRadius; double outerCornerRadius = cornerRadius.TopLeft; // Already validated that all corners have the same radius bool roundedCorners = !DoubleUtil.IsZero(outerCornerRadius); // If we have a brush with which to draw the border, do so. // NB: We double draw corners right now. Corner handling is tricky (bevelling, &c...) and // we need a firm spec before doing "the right thing." (greglett, ffortes) if (!border.IsZero && (borderBrush = BorderBrush) != null) { // Initialize the first pen. Note that each pen is created via new() // and frozen if possible. Doing this avoids the pen // being copied when used in the DrawLine methods. Pen pen = LeftPenCache; if (pen == null) { pen = new Pen(); pen.Brush = borderBrush; if (useLayoutRounding) { pen.Thickness = UIElement.RoundLayoutValue(border.Left, FrameworkElement.DpiScaleX); } else { pen.Thickness = border.Left; } if (borderBrush.IsFrozen) { pen.Freeze(); } LeftPenCache = pen; } double halfThickness; if (border.IsUniform) { halfThickness = pen.Thickness * 0.5; // Create rect w/ border thickness, and round if applying layout rounding. Rect rect = new Rect(new Point(halfThickness, halfThickness), new Point(RenderSize.Width - halfThickness, RenderSize.Height - halfThickness)); if (roundedCorners) { dc.DrawRoundedRectangle( null, pen, rect, outerCornerRadius, outerCornerRadius); } else { dc.DrawRectangle( null, pen, rect); } } else { // Nonuniform border; stroke each edge. if (DoubleUtil.GreaterThan(border.Left, 0)) { halfThickness = pen.Thickness * 0.5; dc.DrawLine( pen, new Point(halfThickness, 0), new Point(halfThickness, RenderSize.Height)); } if (DoubleUtil.GreaterThan(border.Right, 0)) { pen = RightPenCache; if (pen == null) { pen = new Pen(); pen.Brush = borderBrush; if (useLayoutRounding) { pen.Thickness = UIElement.RoundLayoutValue(border.Right, FrameworkElement.DpiScaleX); } else { pen.Thickness = border.Right; } if (borderBrush.IsFrozen) { pen.Freeze(); } RightPenCache = pen; } halfThickness = pen.Thickness * 0.5; dc.DrawLine( pen, new Point(RenderSize.Width - halfThickness, 0), new Point(RenderSize.Width - halfThickness, RenderSize.Height)); } if (DoubleUtil.GreaterThan(border.Top, 0)) { pen = TopPenCache; if (pen == null) { pen = new Pen(); pen.Brush = borderBrush; if (useLayoutRounding) { pen.Thickness = UIElement.RoundLayoutValue(border.Top, FrameworkElement.DpiScaleY); } else { pen.Thickness = border.Top; } if (borderBrush.IsFrozen) { pen.Freeze(); } TopPenCache = pen; } halfThickness = pen.Thickness * 0.5; dc.DrawLine( pen, new Point(0, halfThickness), new Point(RenderSize.Width, halfThickness)); } if (DoubleUtil.GreaterThan(border.Bottom, 0)) { pen = BottomPenCache; if (pen == null) { pen = new Pen(); pen.Brush = borderBrush; if (useLayoutRounding) { pen.Thickness = UIElement.RoundLayoutValue(border.Bottom, FrameworkElement.DpiScaleY); } else { pen.Thickness = border.Bottom; } if (borderBrush.IsFrozen) { pen.Freeze(); } BottomPenCache = pen; } halfThickness = pen.Thickness * 0.5; dc.DrawLine( pen, new Point(0, RenderSize.Height - halfThickness), new Point(RenderSize.Width, RenderSize.Height - halfThickness)); } } } // Draw background in rectangle inside border. Brush background = Background; if (background != null) { // Intialize background Point ptTL, ptBR; if (useLayoutRounding) { ptTL = new Point(UIElement.RoundLayoutValue(border.Left, FrameworkElement.DpiScaleX), UIElement.RoundLayoutValue(border.Top, FrameworkElement.DpiScaleY)); ptBR = new Point(UIElement.RoundLayoutValue(RenderSize.Width - border.Right, FrameworkElement.DpiScaleX), UIElement.RoundLayoutValue(RenderSize.Height - border.Bottom, FrameworkElement.DpiScaleY)); } else { ptTL = new Point(border.Left, border.Top); ptBR = new Point(RenderSize.Width - border.Right, RenderSize.Height - border.Bottom); } // Do not draw background if the borders are so large that they overlap. if (ptBR.X > ptTL.X && ptBR.Y > ptTL.Y) { if (roundedCorners) { Radii innerRadii = new Radii(cornerRadius, border, false); // Determine the inner edge radius double innerCornerRadius = innerRadii.TopLeft; // Already validated that all corners have the same radius dc.DrawRoundedRectangle(background, null, new Rect(ptTL, ptBR), innerCornerRadius, innerCornerRadius); } else { dc.DrawRectangle(background, null, new Rect(ptTL, ptBR)); } } } } }
/// <summary> /// Border computes the position of its single child and applies its child's alignments to the child. /// /// </summary> /// <param name="finalSize">The size reserved for this element by the parent</param> /// <returns>The actual ink area of the element, typically the same as finalSize</returns> protected override Size ArrangeOverride(Size finalSize) { Thickness borders = BorderThickness; Rect boundRect = new Rect(finalSize); Rect innerRect = HelperDeflateRect(boundRect, borders); // arrange child UIElement child = Child; if (child != null) { Rect childRect = HelperDeflateRect(innerRect, Padding); child.Arrange(childRect); } CornerRadius radii = CornerRadius; Brush borderBrush = BorderBrush; bool uniformCorners = AreUniformCorners(radii); // decide which code path to execute. complex (geometry path based) rendering // is used if one of the following is true: // 1. there are non-uniform rounded corners _useComplexRenderCodePath = !uniformCorners; if ( !_useComplexRenderCodePath && borderBrush != null ) { SolidColorBrush originIndependentBrush = borderBrush as SolidColorBrush; bool uniformBorders = borders.IsUniform; _useComplexRenderCodePath = // 2. the border brush is origin dependent (the only origin independent brush is a solid color brush) (originIndependentBrush == null) // 3. the border brush is semi-transtarent solid color brush AND border thickness is not uniform // (for uniform semi-transparent border Border.OnRender draws rectangle outline - so it works fine) || ((originIndependentBrush.Color.A < 0xff) && !uniformBorders) // 4. there are rounded corners AND the border thickness is not uniform || (!DoubleUtil.IsZero(radii.TopLeft) && !uniformBorders); } if (_useComplexRenderCodePath) { Radii innerRadii = new Radii(radii, borders, false); StreamGeometry backgroundGeometry = null; // calculate border / background rendering geometry if (!DoubleUtil.IsZero(innerRect.Width) && !DoubleUtil.IsZero(innerRect.Height)) { backgroundGeometry = new StreamGeometry(); using (StreamGeometryContext ctx = backgroundGeometry.Open()) { GenerateGeometry(ctx, innerRect, innerRadii); } backgroundGeometry.Freeze(); BackgroundGeometryCache = backgroundGeometry; } else { BackgroundGeometryCache = null; } if (!DoubleUtil.IsZero(boundRect.Width) && !DoubleUtil.IsZero(boundRect.Height)) { Radii outerRadii = new Radii(radii, borders, true); StreamGeometry borderGeometry = new StreamGeometry(); using (StreamGeometryContext ctx = borderGeometry.Open()) { GenerateGeometry(ctx, boundRect, outerRadii); if (backgroundGeometry != null) { GenerateGeometry(ctx, innerRect, innerRadii); } } borderGeometry.Freeze(); BorderGeometryCache = borderGeometry; } else { BorderGeometryCache = null; } } else { BackgroundGeometryCache = null; BorderGeometryCache = null; } return (finalSize); }
public Element() { this.RadiusConstants = new Radii(this); }
public RainbowCircleSudoku() { Alphabet = Enumerable.Range(1, 12); Cells = Angles.SelectMany(t => Radii.Select(r => $"{t}{r}")); Conditions = Rings.Concat(Wedges).Concat(Across); }
/// <summary> /// Border computes the position of its single child and applies its child's alignments to the child. /// </summary> /// <param name="finalSize">The size reserved for this element by the parent</param> /// <returns>The actual ink area of the element, typically the same as finalSize</returns> protected override Size ArrangeOverride(Size finalSize) { var borders = BorderThickness; if (UseLayoutRounding) { var dpi = DpiUtil.GetDpi(this); borders = new Thickness(UIElementUtil.RoundLayoutValue(borders.Left, dpi.DpiScaleX), UIElementUtil.RoundLayoutValue(borders.Top, dpi.DpiScaleY), UIElementUtil.RoundLayoutValue(borders.Right, dpi.DpiScaleX), UIElementUtil.RoundLayoutValue(borders.Bottom, dpi.DpiScaleY)); } var boundRect = new Rect(finalSize); var innerRect = RectUtil.Deflate(boundRect, borders); // arrange child var child = Child; if (child != null) { Rect childRect = RectUtil.Deflate(innerRect, Padding); child.Arrange(childRect); } var radius = CornerRadius; useComplexRender = !CornerRadiusUtil.IsUniform(radius) || !ThicknessUtil.IsUniform(borders); backgroundGeometryCache = upperLeftCache = upperRightCache = lowerRightCache = lowerLeftCache = null; if (useComplexRender) { // calculate border / background rendering geometry if (!DoubleUtil.IsZero(boundRect.Width) && !DoubleUtil.IsZero(boundRect.Height)) { var outerRadii = new Radii(boundRect, radius, borders, true); // Upper-right corner var radiusX = boundRect.TopRight.X - outerRadii.TopRight.X; var radiusY = outerRadii.RightTop.Y - boundRect.TopRight.Y; if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) { upperRightCache = GenerateRoundedGeometry(outerRadii.TopRight, outerRadii.RightTop, new Size(radiusX, radiusY)); } // Lower-right corner radiusX = boundRect.BottomRight.X - outerRadii.BottomRight.X; radiusY = boundRect.BottomRight.Y - outerRadii.RightBottom.Y; if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) { lowerRightCache = GenerateRoundedGeometry(outerRadii.RightBottom, outerRadii.BottomRight, new Size(radiusX, radiusY)); } // Lower-left corner radiusX = outerRadii.BottomLeft.X - boundRect.BottomLeft.X; radiusY = boundRect.BottomLeft.Y - outerRadii.LeftBottom.Y; if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) { lowerLeftCache = GenerateRoundedGeometry(outerRadii.BottomLeft, outerRadii.LeftBottom, new Size(radiusX, radiusY)); } // Upper-left corner radiusX = outerRadii.TopLeft.X - boundRect.TopLeft.X; radiusY = outerRadii.LeftTop.Y - boundRect.TopLeft.Y; if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) { upperLeftCache = GenerateRoundedGeometry(outerRadii.LeftTop, outerRadii.TopLeft, new Size(radiusX, radiusY)); } } if (!DoubleUtil.IsZero(innerRect.Width) && !DoubleUtil.IsZero(innerRect.Height)) { var innerRadii = new Radii(innerRect, radius, borders, false); var backgroundGeometry = new StreamGeometry(); using (StreamGeometryContext sc = backgroundGeometry.Open()) { // create the border geometry sc.BeginFigure(innerRadii.TopLeft, true /* is filled */, true /* is closed */); // Top line sc.LineTo(innerRadii.TopRight, true /* is stroked */, false /* is smooth join */); // Upper-right corners var radiusX = innerRect.TopRight.X - innerRadii.TopRight.X; var radiusY = innerRadii.RightTop.Y - innerRect.TopRight.Y; if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) { sc.ArcTo(innerRadii.RightTop, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false); } // Right line sc.LineTo(innerRadii.RightBottom, true /* is stroked */, false /* is smooth join */); // Lower-right corners radiusX = innerRect.BottomRight.X - innerRadii.BottomRight.X; radiusY = innerRect.BottomRight.Y - innerRadii.RightBottom.Y; if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) { sc.ArcTo(innerRadii.BottomRight, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false); } // Bottom line sc.LineTo(innerRadii.BottomLeft, true /* is stroked */, false /* is smooth join */); // Lower-left corners radiusX = innerRadii.BottomLeft.X - innerRect.BottomLeft.X; radiusY = innerRect.BottomLeft.Y - innerRadii.LeftBottom.Y; if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) { sc.ArcTo(innerRadii.LeftBottom, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false); } // Left line sc.LineTo(innerRadii.LeftTop, true /* is stroked */, false /* is smooth join */); // Upper-left corners radiusX = innerRadii.TopLeft.X - innerRect.TopLeft.X; radiusY = innerRadii.LeftTop.Y - innerRect.TopLeft.Y; if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY)) { sc.ArcTo(innerRadii.TopLeft, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false); } } backgroundGeometry.Freeze(); backgroundGeometryCache = backgroundGeometry; } } return(finalSize); }