CanvasGeometry MakeCircleGeometry() { bool first = true; Rect bounds; foreach (var point in currentPointsInContact.Values) { if (first) { bounds = new Rect(point, point); first = false; } else { bounds.Union(point); } } var radius = Math.Max(bounds.Width, bounds.Height) * 0.5; if (radius == 0) { radius = 50; } var center = new Vector2((float)(bounds.Left + bounds.Width * 0.5), (float)(bounds.Top + bounds.Height * 0.5)); return(CanvasGeometry.CreateCircle(device, center, (float)radius)); }
private void StartClip(Visual visual, bool show, Vector2 desiredSize) { var actualWidth = desiredSize.X; var actualHeight = desiredSize.Y; var left = (float)Padding.Left; var top = (float)Padding.Top; var width = MathF.Max(actualWidth - left, actualHeight - top); var diaginal = MathF.Sqrt((width * width) + (width * width)); var device = CanvasDevice.GetSharedDevice(); var rect1 = CanvasGeometry.CreateRectangle(device, 0, 0, show ? 0 : actualWidth, show ? 0 : actualHeight); var elli1 = CanvasGeometry.CreateCircle(device, left, top, 0); var group1 = CanvasGeometry.CreateGroup(device, new[] { elli1, rect1 }, CanvasFilledRegionDetermination.Alternate); var elli2 = CanvasGeometry.CreateCircle(device, left, top, diaginal); var group2 = CanvasGeometry.CreateGroup(device, new[] { elli2, rect1 }, CanvasFilledRegionDetermination.Alternate); var ellipse = Window.Current.Compositor.CreatePathGeometry(new CompositionPath(group2)); var clip = Window.Current.Compositor.CreateGeometricClip(ellipse); var ease = Window.Current.Compositor.CreateCubicBezierEasingFunction(new Vector2(.42f, 0), new Vector2(1, 1)); var anim = Window.Current.Compositor.CreatePathKeyFrameAnimation(); anim.InsertKeyFrame(0, new CompositionPath(group1), ease); anim.InsertKeyFrame(1, new CompositionPath(group2), ease); anim.Duration = TimeSpan.FromMilliseconds(500); ellipse.StartAnimation("Path", anim); visual.Clip = clip; }
public void AddCircle(float x, float y, float radius) { InvalidateGeometry(); var geometry = CanvasGeometry.CreateCircle(Device, x, y, radius); AddGeometry(geometry); }
/// <summary> /// /// </summary> /// <param name="appCtx"></param> /// <param name="canvas"></param> /// <param name="drawableEdges"></param> /// <param name="drawableVertices"></param> public static void LayoutDGraphRandom( AppContext appCtx, CanvasControl canvas, Dictionary <Guid, DrawableEdge> drawableEdges, Dictionary <Guid, DrawableVertex> drawableVertices) { drawableEdges.Clear(); drawableVertices.Clear(); foreach (KeyValuePair <Guid, UVertex> kvp in appCtx.CurrentGraph.Vertices) { Int32 min_x = Defines.VERTEX_SIZE; Int32 min_y = Defines.VERTEX_SIZE; Int32 max_x = 0; Int32 max_y = 0; if (appCtx.FitGraphToView == true) { max_x = (Int32)canvas.ActualWidth - Defines.VERTEX_SIZE; max_y = (Int32)canvas.ActualHeight - Defines.VERTEX_SIZE; } else { max_x = Defines.VERTEX_SIZE * (appCtx.CurrentGraph.Vertices.Count + Defines.MAX_VERTEX_SPACE); max_y = Defines.VERTEX_SIZE * (appCtx.CurrentGraph.Vertices.Count + Defines.MAX_VERTEX_SPACE); } Vector2 circlePos = new Vector2(appCtx.RandomSource.Next(min_x, max_x), appCtx.RandomSource.Next(min_y, max_y)); DrawableVertex dn = new DrawableVertex { Position = circlePos, VertexId = kvp.Value.VertexId, Circle = CanvasGeometry.CreateCircle(canvas, circlePos, Defines.VERTEX_SIZE) }; drawableVertices[dn.VertexId] = dn; } foreach (KeyValuePair <Guid, UEdge> kvp in appCtx.CurrentGraph.Edges) { CanvasPathBuilder pathBuilder = new CanvasPathBuilder(canvas); DrawableEdge de = new DrawableEdge { EdgeId = kvp.Value.EdgeId, HeadVertexId = kvp.Value.HeadVertexId, TailVertexId = kvp.Value.TailVertexId, }; de.HeadPosition = drawableVertices[de.HeadVertexId].Position; de.TailPosition = drawableVertices[de.TailVertexId].Position; pathBuilder.BeginFigure(de.HeadPosition); pathBuilder.AddLine(de.TailPosition); pathBuilder.EndFigure(CanvasFigureLoop.Open); de.Line = CanvasGeometry.CreatePath(pathBuilder); drawableEdges[de.EdgeId] = de; } canvas.Invalidate(); }
public void CreateResources(ICanvasResourceCreator resourceCreator) { DestroyResources(); // create stroke _strokeStyle = new CanvasStrokeStyle(); // create geometry var body = CanvasGeometry.CreateCircle(resourceCreator, new Vector2(0.0f), 24); var cannon = CanvasGeometry.CreateRectangle(resourceCreator, 23, -3, 10, 6); var comb = body.CombineWith(cannon, Matrix3x2.Identity, CanvasGeometryCombine.Union); // cache _geo = CanvasCachedGeometry.CreateStroke(comb, Style.StrokeWidth, _strokeStyle); }
private CanvasGeometry?CreateOverlayMask(IDrawingCanvas sender) { var _canvas = sender; if (_canvas == null) { return(null); } return(CanvasGeometry .CreateCircle(sender, _canvas.Center.ToVector2() * _canvas.Size.ToVector2(), (float)(OuterRadius * _canvas.Size.Height)) .CombineWith( CanvasGeometry.CreateRectangle(sender, Bounds.GetRectangle(_canvas)), Matrix3x2.Identity, CanvasGeometryCombine.Intersect) .CombineWith( CanvasGeometry.CreateCircle(sender, _canvas.Center.ToVector2() * _canvas.Size.ToVector2(), (float)(InnerRadius * _canvas.Size.Height)), Matrix3x2.Identity, CanvasGeometryCombine.Exclude )); }
private CanvasGeometry CreateCanvasGeometry(CanvasVirtualControl device) { switch (GeometryType) { case GeometryType.Rectangle: return(CanvasGeometry.CreateRectangle(device, (float)Points[0].X, (float)Points[0].Y, (float)MapController.Instance.MousePosition.X - (float)Points[0].X, (float)MapController.Instance.MousePosition.Y - (float)Points[0].Y)); case GeometryType.Line: CanvasPathBuilder pathBuilder = new CanvasPathBuilder(device); pathBuilder.SetSegmentOptions(CanvasFigureSegmentOptions.ForceRoundLineJoin); pathBuilder.BeginFigure((float)Points[0].X, (float)Points[0].Y); pathBuilder.AddLine(new Vector2((float)MapController.Instance.MousePosition.X, (float)MapController.Instance.MousePosition.Y)); pathBuilder.EndFigure(CanvasFigureLoop.Open); return(CanvasGeometry.CreatePath(pathBuilder)); case GeometryType.Circle: return(CanvasGeometry.CreateCircle(device, new Vector2((float)Points[0].X, (float)Points[0].Y), GetSegmentLength.CalculateSegmentLength(Points[0], MapController.Instance.MousePosition))); } return(null); }
public void LayoutGraphRandom(CanvasControl canvas) { this.Layout = DrawableGraphLayout.Random; foreach (KeyValuePair <UInt32, GraphVertex> kvp in this.Vertices) { UInt32 minX = Defines.VERTEX_SIZE; UInt32 minY = Defines.VERTEX_SIZE; UInt32 maxX = 0; UInt32 maxY = 0; UInt32 paddingValue = Defines.VERTEX_SIZE - Defines.MAX_VERT_SPACE; if (this.FitToView == true) { maxX = (UInt32)canvas.ActualWidth - paddingValue; maxY = (UInt32)canvas.ActualHeight - paddingValue; } else { maxX = Defines.VERTEX_SIZE * ((UInt32)this.Vertices.Count + Defines.MAX_VERT_SPACE); maxY = maxX; } kvp.Value.Position = new Vector2( this.rng.Next((Int32)minX, (Int32)maxX), this.rng.Next((Int32)minY, (Int32)maxY)); kvp.Value.Circle = CanvasGeometry.CreateCircle(canvas, kvp.Value.Position, kvp.Value.VertexSize); } foreach (KeyValuePair <UInt32, GraphEdge> kvp in this.Edges) { CanvasPathBuilder pathBuilder = new CanvasPathBuilder(canvas); kvp.Value.HeadPosition = this.Vertices[kvp.Value.HeadVertexId].Position; kvp.Value.TailPosition = this.Vertices[kvp.Value.TailVertexId].Position; pathBuilder.BeginFigure(kvp.Value.HeadPosition); pathBuilder.AddLine(kvp.Value.TailPosition); pathBuilder.EndFigure(CanvasFigureLoop.Open); kvp.Value.Line = CanvasGeometry.CreatePath(pathBuilder); } }
private void DrawIdleBg(CanvasDrawingSession ds) { Easings.ParamTween(ref BgY_c, BgY_t, 0.85f, 0.15f); BgFillRect.Y = BgY_c; Easings.ParamTween(ref BgR_c, BgR_t, 0.75f, 0.25f); if (BgR_c < 0) { ds.DrawImage(BgBmp, StageRect, BgFillRect); ds.FillRectangle(StageRect, MaskBrush); } else { ds.DrawImage(BgBmp, StageRect, BgFillRect); CanvasGeometry MaskFill = CanvasGeometry.CreateRectangle(ds, StageRect); CanvasGeometry DrillMask = CanvasGeometry.CreateCircle(ds, PCenter, BgR_c); CanvasGeometry Combined = MaskFill.CombineWith(DrillMask, Matrix3x2.CreateTranslation(0, 0), CanvasGeometryCombine.Exclude); ds.FillGeometry(Combined, MaskBrush); } }
private void CreateCanvasGeometry(CanvasVirtualControl device) { switch (GeometryType) { case GeometryType.Rectangle: _geometry = CanvasGeometry.CreateRectangle(device, (float)Points[0].X, (float)Points[0].Y, (float)Points[1].X - (float)Points[0].X, (float)Points[1].Y - (float)Points[0].Y); break; case GeometryType.Line: _geometry = CanvasGeometry.CreatePolygon(device, new Vector2[] { new Vector2((float)Points[0].X, (float)Points[0].Y), new Vector2((float)Points[1].X, (float)Points[1].Y) }); break; case GeometryType.Circle: _geometry = CanvasGeometry.CreateCircle(device, new Vector2((float)Points[0].X, (float)Points[0].Y), GetSegmentLength.CalculateSegmentLength(Points[0], Points[1])); break; } }
public static CanvasGeometry CreateCircle(ICanvasResourceCreator resourceCreator) { return(CanvasGeometry.CreateCircle(resourceCreator, 500, 20, 20)); }
private async void OnPageLoaded(object sender, RoutedEventArgs e) { _compositor = Window.Current.Compositor; _generator = _compositor.CreateCompositionGenerator(); var gridSize = new Vector2((float)RootGrid.ActualWidth, (float)RootGrid.ActualHeight); var anim = _compositor.CreatePathKeyFrameAnimation(); _rootVisual = _compositor.CreateSpriteVisual(); _rootVisual.Size = gridSize; // Create the surface brush from the image var imageSurface = await _generator.CreateImageSurfaceAsync( new Uri("ms-appx:///Assets/Images/Cat.png"), new Size(400, 400), ImageSurfaceOptions.Default); var imageBrush = _compositor.CreateSurfaceBrush(imageSurface); // Create the clipped visuals for (var i = 0; i < 145; i++) { var visual = _compositor.CreateSpriteVisual(); visual.Offset = new Vector3(400, 400, 0); visual.Size = new Vector2(400, 400); visual.Brush = imageBrush; visual.AnchorPoint = new Vector2(0.5f); var radius = 290 - (i * 2); // Create the GeometricClip for this visual var clipGeometry = CanvasGeometry.CreateCircle(null, new Vector2(200, 200), radius); visual.Clip = _compositor.CreateGeometricClip(clipGeometry); _rootVisual.Children.InsertAtTop(visual); _visuals.Add(visual); } // Display the rootVisual ElementCompositionPreview.SetElementChildVisual(RootGrid, _rootVisual); // Reverse the visuals list so that the items in the list are now sorted // in z-order from top to bottom _visuals.Reverse(); // The topmost visual would track the pointer position _dragVisual = _visuals.First(); // Get the CompositionPropertySet which tracks the pointer position on the RootGrid _pointerTrackerSet = ElementCompositionPreview.GetPointerPositionPropertySet(RootGrid); // Animate the topmost visual so that it tracks and follows the pointer position _pointerTrackerAnimation = _compositor.GenerateVector3KeyFrameAnimation() .HavingDuration(PointerTrackerAnimationDuration) .RepeatsForever(); _pointerTrackerAnimation.InsertExpressionKeyFrame(0f, c => new VisualTarget().Offset); _pointerTrackerAnimation.InsertExpressionKeyFrame( 1f, c => c.Lerp(new VisualTarget().Offset, _pointerTrackerSet.Get <Vector3>("Position"), DefaultLerpAmount), _compositor.CreateEaseOutQuinticEasingFunction()); // Animate the remaining visuals in such a way that each visual tracks and follows the // position of the visual above it. var prevChild = _dragVisual; foreach (var child in _visuals.Skip(1)) { var offsetAnimation = _compositor.GenerateVector3KeyFrameAnimation() .HavingDuration(ChildOffsetAnimationDuration) .RepeatsForever(); offsetAnimation.InsertExpressionKeyFrame(0f, c => new VisualTarget().Offset); offsetAnimation.InsertExpressionKeyFrame( 1f, c => c.Lerp(new VisualTarget().Offset, prevChild.Offset, DefaultLerpAmount), _compositor.CreateEaseOutQuinticEasingFunction()); child.StartAnimation(() => child.Offset, offsetAnimation); prevChild = child; } }
/// <summary> /// Handles the Arrange layout phase /// </summary> /// <param name="finalSize">Final Size of the control</param> /// <returns>Size</returns> protected override Size ArrangeOverride(Size finalSize) { if ((_compositor == null) || (_generator == null)) { return(base.ArrangeOverride(finalSize)); } if (Double.IsInfinity(finalSize.Width) || Double.IsInfinity(finalSize.Height) || Double.IsNaN(finalSize.Width) || Double.IsNaN(finalSize.Height)) { return(base.ArrangeOverride(finalSize)); } // Stop the animations and dispose the previous nodes // and their animations if (_isAnimationStarted) { for (var i = 0; i < _nodes.Count; i++) { _nodes[i].StopAnimation(AnimatedProperty); _animations[i].Dispose(); _animations[i] = null; _nodes[i].Dispose(); _nodes[i] = null; } _container.StopAnimation(AnimatedProperty); _containerAnimation.Dispose(); _containerAnimation = null; _container.Dispose(); _container = null; _animations.Clear(); _nodes.Clear(); _isAnimationStarted = false; } // Validate MaxNodes and ActiveNodes if ((MaxNodes <= 0) || (ActiveNodes <= 0)) { return(finalSize); } // Coerce ActiveNodes to MaxNodes if ActiveNodes > MaxNodes if (ActiveNodes > MaxNodes) { ActiveNodes = MaxNodes; } // Take the smallest of the width or height var sideLength = (float)Math.Min(finalSize.Width, finalSize.Height); // Size of the progress ring displayed _ringSize = new Vector2(sideLength, sideLength); var sideHalf = sideLength / 2f; // Radius of each node _nodeRadius = (float)NodeSizeFactor * sideHalf; // Size of each node _nodeSize = new Vector2(_nodeRadius * 2f, _nodeRadius * 2f); // Radius of the node _ringRadius = sideHalf - _nodeRadius; // Each animation will consist of '_maxFrameBlocks' number of // FrameBlocks. Each FrameBlock will consist of keyframes which allow // the element being animated to move to the next slot and wait // at that slot until all other elements have moved to their next slot. // Each FrameBlock (except the last one) will have '_maxFramesPerBlock' // number of keyframes. The last keyframe in the last FrameBlock // will always be (1f, "this.StartingValue + 360") // Total number of FrameBlocks in each animation _maxFrameBlocks = ActiveNodes; // Total keyframes in each FrameBlock _maxFramesPerBlock = ActiveNodes + 1; // Total keyframes in each animation _maxKeyFrames = _maxFrameBlocks * _maxFramesPerBlock; // Normalized Progress Key unit value for each keyframe _keyFrameSlice = 1f / _maxKeyFrames; // ======================================================================== // NOTE: // gamma * maxNodes = 360 // gamma = alpha + beta // beta = 2 * Asin(nodeRadius / ringRadius) * (180 / Math.PI) // invisibleNodes = MaxNodes - ActiveNodes // phi = (invisibleNodes * gamma) // theta = phi - beta // ======================================================================== // gamma is the angle between adjacent nodes when maxNodes number of nodes are arranged in a circle _gamma = 360f / MaxNodes; // beta is the angle a node must travel after hitting the adjacent node _beta = 2f * (float)(Math.Asin(_nodeRadius / _ringRadius) * (180f / Math.PI)); // alpha is the smallest angle a node must travel before hitting the adjacent node _alpha = _gamma - _beta; // phi is the angle occupied by (MaxNodes - ActiveNodes) number of nodes _phi = (MaxNodes - ActiveNodes + 1) * _gamma; // theta is the largest angle a node must travel before hitting the adjacent node _theta = _phi - _beta; // Create the Animations _animations = CreateAnimations(); // Create the Container _container = _compositor.CreateContainerVisual(); _container.Size = _ringSize; _container.Offset = new Vector3(((float)finalSize.Width - sideLength) / 2f, ((float)finalSize.Height - sideLength) / 2f, 0f); _container.CenterPoint = new Vector3(_ringSize.X / 2f, _ringSize.Y / 2f, 0f); // Create the Nodes var offset = new Vector3(_nodeRadius, _ringSize.Y / 2f, 0); var centerPoint = new Vector3(_ringSize.X / 2f - _nodeRadius, 0, 0); _nodes = new List <SpriteVisual>(); var geometry = CanvasGeometry.CreateCircle(_generator.Device, new Vector2(_nodeRadius, _nodeRadius), _nodeRadius); // Create/Update the nodeMask var color = NodeColor; if (_nodeMask == null) { //Task.Run(async () => // { _nodeMask = _generator.CreateGeometrySurface(_nodeSize.ToSize(), geometry, color); // }) //.Wait(); } else { //Task.Run(async () => // { _nodeMask.Redraw(_nodeSize.ToSize(), geometry, color); // }) //.Wait(); } // Create the SurfaceBrush for the nodes var brush = _compositor.CreateSurfaceBrush(_nodeMask.Surface); var baseAngle = 0f; // Create the visuals for the nodes for (var i = 0; i < _maxFramesPerBlock; i++) { var node = _compositor.CreateSpriteVisual(); node.Size = _nodeSize; node.AnchorPoint = new Vector2(0.5f); node.Offset = offset; node.CenterPoint = centerPoint; node.Brush = brush; node.RotationAngleInDegrees = baseAngle; if (i == 0) { baseAngle += _phi; } else if (i == _maxFramesPerBlock - 2) { baseAngle = -_beta; } else { baseAngle += _gamma; } _nodes.Add(node); // Add the visual to the container _container.Children.InsertAtTop(node); } // Add the container to the Visual Tree ElementCompositionPreview.SetElementChildVisual(this, _container); // Start Node animations for (var i = 0; i < _maxFramesPerBlock; i++) { _nodes[i].StartAnimation(AnimatedProperty, _animations[i]); } // Start container animation _containerAnimation = _compositor.CreateScalarKeyFrameAnimation(); _containerAnimation.InsertExpressionKeyFrame(1f, "this.StartingValue + 360f", _compositor.CreateLinearEasingFunction()); _containerAnimation.Duration = RingDuration; _containerAnimation.IterationBehavior = AnimationIterationBehavior.Forever; _container.StartAnimation(AnimatedProperty, _containerAnimation); _isAnimationStarted = true; return(finalSize); }
public static CanvasGeometry GetDotGeometry(ICanvasResourceCreator resourceCreator, DotShape shape, Vector2 point, float dotWidth, float dotHeight) { return(CanvasGeometry.CreateCircle(resourceCreator, point, dotWidth / 2)); }
public void CreateLoadingWave(Microsoft.Graphics.Canvas.UI.Xaml.ICanvasAnimatedControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasAnimatedDrawEventArgs args, Vector2 position, Color color) { if (rate >= 10) { percent++; rate = 0; } if (percent > 100) { percent = 0; } CanvasTextLayout textLayout = new CanvasTextLayout(sender, $"{percent}", new CanvasTextFormat() { FontSize = RadiusValue }, RadiusValue * 2, RadiusValue * 2); CanvasGeometry orignalText = CanvasGeometry.CreateText(textLayout); var rectText = orignalText.ComputeBounds(); var textOffsetX = (RadiusValue * 2 - textLayout.LayoutBoundsIncludingTrailingWhitespace.Width) / 2; var textOffsetY = (RadiusValue * 2 - textLayout.LayoutBoundsIncludingTrailingWhitespace.Height) / 2; orignalText = orignalText.Transform(Matrix3x2.CreateTranslation((float)textOffsetX + position.X, (float)textOffsetY + position.Y)); CanvasPathBuilder builder = new CanvasPathBuilder(sender); var offsetY = 2 * rate / 10 + percent * 2; builder.BeginFigure(0 + offsetX + position.X, RadiusValue * 2 - offsetY + position.Y); builder.AddCubicBezier(new Vector2(RadiusValue * 1 + offsetX + position.X, RadiusValue * 2 + RadiusValue / 3 - offsetY + position.Y), new Vector2(RadiusValue * 1 + offsetX + position.X, RadiusValue * 2 - RadiusValue / 3 - offsetY + position.Y), new Vector2(RadiusValue * 2 + offsetX + position.X, RadiusValue * 2 - offsetY + position.Y)); builder.AddCubicBezier(new Vector2(RadiusValue * 3 + offsetX + position.X, RadiusValue * 2 + RadiusValue / 3 - offsetY + position.Y), new Vector2(RadiusValue * 3 + offsetX + position.X, RadiusValue * 2 - RadiusValue / 3 - offsetY + position.Y), new Vector2(RadiusValue * 4 + offsetX + position.X, RadiusValue * 2 - offsetY + position.Y)); builder.AddLine(RadiusValue * 4 + offsetX + position.X, RadiusValue * 4 + position.Y); builder.AddLine(0 + offsetX + position.X, RadiusValue * 4 + position.Y); builder.EndFigure(CanvasFigureLoop.Closed); var wavePath = CanvasGeometry.CreatePath(builder); var circlePath = CanvasGeometry.CreateCircle(sender, new Vector2(RadiusValue, RadiusValue), RadiusValue); var backgroundPath = circlePath.CombineWith(wavePath, Matrix3x2.Identity, CanvasGeometryCombine.Intersect); var topText = orignalText.CombineWith(backgroundPath, Matrix3x2.Identity, CanvasGeometryCombine.Exclude); var drawnText = orignalText.CombineWith(backgroundPath, Matrix3x2.Identity, CanvasGeometryCombine.Intersect); args.DrawingSession.FillGeometry(backgroundPath, position, color); args.DrawingSession.FillGeometry(topText, color); args.DrawingSession.FillGeometry(drawnText, Colors.White); var borderCircle = CanvasGeometry.CreateCircle(sender, new Vector2(RadiusValue, RadiusValue), RadiusValue - 1); args.DrawingSession.DrawGeometry(borderCircle, position, color); offsetX--; if (offsetX <= -RadiusValue * 2) { offsetX = 0; } rate++; }
private CanvasCachedGeometry CreateCachedGeometry(float scale, float thickness, float factor = 0.5f) { CanvasDevice device = CanvasDevice.GetSharedDevice(); if (device == null) { return(null); } CanvasPathBuilder pathBuilder = new CanvasPathBuilder(device); pathBuilder.SetFilledRegionDetermination(CanvasFilledRegionDetermination.Winding); float maxThickness = thickness; float minThickness = thickness / 5; bool closedPath = false; int count = points.Count; for (int i = 0; i < count; i++) { // 끝점 2개가 완전히 일치하면 하나만 넣는다. if (i > 0 && i == count - 1 && (points[i].X == points[i - 1].X && points[i].Y == points[i - 1].Y)) { continue; } else { float force = points[i].Force; force = (force < 0) ? 0 : points[i].Force; force = (force > 1.0f) ? 1.0f : points[i].Force; // 점의 두께 차이가 최대 4배가 되도록 조정 //float normalForce = 0.2 + ( force * 0.6 ); // 0.2 ~ 0.8 midPoints.Add(points[i]); //midPoints.Add(new Point(new Point(points[i].X, points[i].Y, force), scale)); } } //if (points.Count > midPoints.Count) // Debug.WriteLine("filtered : " + (points.Count - midPoints.Count)); count = midPoints.Count; // 선 두께에 비해 가까운 점이나 라인상 거의 필요가 없다고 판단되는 점을 지우는 부분 if (midPoints.Count > 2) { Simplify(midPoints, maxThickness); } //if (count > midPoints.Count) // Debug.WriteLine("simplify : " + (count - midPoints.Count)); count = midPoints.Count; // 처음과 끝에 펜 구동상 꼬리가 생기는 경우 꼬리를 판단해서 제거하는 부분 // 꼬리는 없을수도 있다. // 미완성 if (midPoints.Count > 2) { RemoveTail(midPoints, maxThickness); } //if (count > midPoints.Count) // Debug.WriteLine("removeTail : " + (count - midPoints.Count)); count = midPoints.Count; // 점 제거 로직 후 점이 하나만 남으면 원으로 그린다. // Neo Studio에서는 점이 하나일때 가까운 점을 하나 더 추가하여 2점 처리를 한다. if (count == 1) { float force = midPoints[0].Force < 0.3f ? 0.3f : midPoints[0].Force; //float r = maxThickness * force * 3.0f * 1.5f; float p = PenInkFactor * Pixel2DotScaleFactor * force * scale * maxThickness; using (var geom = CanvasGeometry.CreateCircle(device, midPoints[0].X, midPoints[0].Y, p / 2)) { return(CanvasCachedGeometry.CreateFill(geom)); } } else { GetControlPoint(midPoints, midPoints.Count, closedPath, factor); GetSplitPoints(midPoints, 0.1f, 60); count = midPoints.Count; for (int i = 0; i < count; i++) { float px = midPoints[i].OutX - midPoints[i].InX; float py = midPoints[i].OutY - midPoints[i].InY; float dp = midPoints[i].GetDistanceInOut(); float pp = maxThickness * midPoints[i].Force; pp *= 1.5f; if (pp < minThickness) { pp = minThickness; } // 첫점과 끝점 처리 if (i == 0) { px = midPoints[i + 1].X - midPoints[i].X; py = midPoints[i + 1].Y - midPoints[i].Y; dp = (float)Math.Sqrt(px * px + py * py); } else if (i == midPoints.Count - 1) { px = midPoints[i].X - midPoints[i - 1].X; py = midPoints[i].Y - midPoints[i - 1].Y; dp = (float)Math.Sqrt(px * px + py * py); } if (dp != 0) { rightPoints.Add(new DrawablePoint(midPoints[i].X - (py * pp / dp), midPoints[i].Y + (px * pp / dp), midPoints[i].Force)); leftPoints.Add(new DrawablePoint(midPoints[i].X + (py * pp / dp), midPoints[i].Y - (px * pp / dp), midPoints[i].Force)); } else { rightPoints.Add(new DrawablePoint(midPoints[i].X, midPoints[i].Y, midPoints[i].Force)); leftPoints.Add(new DrawablePoint(midPoints[i].X, midPoints[i].Y, midPoints[i].Force)); } } GetControlPoint(leftPoints, leftPoints.Count, true, factor); GetControlPoint(rightPoints, rightPoints.Count, true, factor); foreach (var pt in leftPoints) { pt.SetScale(scale / 56f); } foreach (var pt in rightPoints) { pt.SetScale(scale / 56f); } DrawPath(pathBuilder, leftPoints, rightPoints); using (var geom = CanvasGeometry.CreatePath(pathBuilder)) { return(CanvasCachedGeometry.CreateFill(geom)); } } }
private CanvasCachedGeometry CreateCachedGeometryPreviousVersion(float scale, float thickness) { CanvasDevice device = CanvasDevice.GetSharedDevice(); if (device == null) { return(null); } foreach (var pt in points) { midPoints.Add(new DrawablePoint(pt.X / 56f, pt.Y / 56f, pt.Force * pt.MaxForce)); } var dots = midPoints; if (dots.Count <= 2) { float p = CalcForce(dots[0].Force, scale, thickness); if (dots.Count == 1) // 점찍기 { using (var geom = CanvasGeometry.CreateCircle(device, dots[0].X * scale, dots[0].Y * scale, p / 2)) { return(CanvasCachedGeometry.CreateFill(geom)); } } else if (dots.Count == 2) // 선그리기 { float p2 = CalcForce(dots[0].Force, scale, thickness); CanvasPathBuilder pathBuilder = new CanvasPathBuilder(device); pathBuilder.SetFilledRegionDetermination(CanvasFilledRegionDetermination.Winding); pathBuilder.BeginFigure(dots[0].X * scale, dots[0].Y * scale); pathBuilder.AddLine(dots[1].X * scale, dots[1].Y * scale); pathBuilder.EndFigure(CanvasFigureLoop.Open); using (var geom = CanvasGeometry.CreatePath(pathBuilder)) { return(CanvasCachedGeometry.CreateStroke(geom, (p + p2) / 2, GetStrokesStyle())); } } } else { float x0, x1, x2, x3, y0, y1, y2, y3, p0, p1, p2, p3; float vx01, vy01, vx21, vy21; float norm; float n_x0, n_y0, n_x2, n_y2; x0 = dots[0].X * scale + 0.1f; y0 = dots[0].Y * scale; // TODO Change MaxForce //p0 = (float)dots[0].Force / 1024 * width; p0 = CalcForce(dots[0].Force, scale, thickness) / 2; x1 = dots[1].X * scale + 0.1f; y1 = dots[1].Y * scale; //p1 = (float)dots[1].Force / 1024 * width; p1 = CalcForce(dots[1].Force, scale, thickness) / 2; vx01 = x1 - x0; vy01 = y1 - y0; // instead of dividing tangent/norm by two, we multiply norm by 2 norm = (float)Math.Sqrt(vx01 * vx01 + vy01 * vy01 + 0.0001f) * 2f; //vx01 = vx01 / norm * scaled_pen_thickness * p0; //vy01 = vy01 / norm * scaled_pen_thickness * p0; vx01 = vx01 / norm * p0; vy01 = vy01 / norm * p0; n_x0 = vy01; n_y0 = -vx01; CanvasPathBuilder pathBuilder = new CanvasPathBuilder(device); pathBuilder.SetFilledRegionDetermination(CanvasFilledRegionDetermination.Winding); int count = dots.Count; for (int i = 2; i < count; ++i) { x3 = dots[i].X * scale + 0.1f; y3 = dots[i].Y * scale; //p3 = (float)dots[i].Force / 1024 * width; //p3 = CalcForce(dots[i].Force, scale, thickness) / 2; p3 = dots[i].Force; x2 = (x1 + x3) / 2.0f; y2 = (y1 + y3) / 2.0f; p2 = (p1 + p3) / 2.0f; vx21 = x1 - x2; vy21 = y1 - y2; norm = (float)System.Math.Sqrt(vx21 * vx21 + vy21 * vy21 + 0.0001f) * 2.0f; vx21 = vx21 / norm * CalcForce(p2, scale, thickness); vy21 = vy21 / norm * CalcForce(p2, scale, thickness); n_x2 = -vy21; n_y2 = vx21; //pathBuilder = new CanvasPathBuilder(crt.Device); pathBuilder.BeginFigure(x0 + n_x0, y0 + n_y0); // The + boundary of the stroke pathBuilder.AddCubicBezier(new Vector2(x1 + n_x0, y1 + n_y0), new Vector2(x1 + n_x2, y1 + n_y2), new Vector2(x2 + n_x2, y2 + n_y2)); // round out the cap pathBuilder.AddCubicBezier(new Vector2(x2 + n_x2 - vx21, y2 + n_y2 - vy21), new Vector2(x2 - n_x2 - vx21, y2 - n_y2 - vy21), new Vector2(x2 - n_x2, y2 - n_y2)); // THe - boundary of the stroke pathBuilder.AddCubicBezier(new Vector2(x1 - n_x2, y1 - n_y2), new Vector2(x1 - n_x0, y1 - n_y0), new Vector2(x0 - n_x0, y0 - n_y0)); // round out the other cap pathBuilder.AddCubicBezier(new Vector2(x0 - n_x0 - vx01, y0 - n_y0 - vy01), new Vector2(x0 + n_x0 - vx01, y0 + n_y0 - vy01), new Vector2(x0 + n_x0, y0 + n_y0)); pathBuilder.EndFigure(CanvasFigureLoop.Open); x0 = x2; y0 = y2; p0 = p2; x1 = x3; y1 = y3; p1 = p3; vx01 = -vx21; vy01 = -vy21; n_x0 = n_x2; n_y0 = n_y2; } x2 = dots[count - 1].X * scale + 0.1f; y2 = dots[count - 1].Y * scale; p2 = dots[count - 1].Force; vx21 = x1 - x2; vy21 = y1 - y2; norm = (float)Math.Sqrt(vx21 * vx21 + vy21 * vy21 + 0.0001f) * 2f; vx21 = vx21 / norm * CalcForce(p2, scale, thickness); vy21 = vy21 / norm * CalcForce(p2, scale, thickness); n_x2 = -vy21; n_y2 = vx21; pathBuilder.BeginFigure(x0 + n_x0, y0 + n_y0); pathBuilder.AddCubicBezier(new Vector2(x1 + n_x0, y1 + n_y0), new Vector2(x1 + n_x2, y1 + n_y2), new Vector2(x2 + n_x2, y2 + n_y2)); pathBuilder.AddCubicBezier(new Vector2(x2 + n_x2 - vx21, y2 + n_y2 - vy21), new Vector2(x2 - n_x2 - vx21, y2 - n_y2 - vy21), new Vector2(x2 - n_x2, y2 - n_y2)); pathBuilder.AddCubicBezier(new Vector2(x1 - n_x2, y1 - n_y2), new Vector2(x1 - n_x0, y1 - n_y0), new Vector2(x0 - n_x0, y0 - n_y0)); pathBuilder.AddCubicBezier(new Vector2(x0 - n_x0 - vx01, y0 - n_y0 - vy01), new Vector2(x0 + n_x0 - vx01, y0 + n_y0 - vy01), new Vector2(x0 + n_x0, y0 + n_y0)); pathBuilder.EndFigure(CanvasFigureLoop.Open); using (var geom = CanvasGeometry.CreatePath(pathBuilder)) { return(CanvasCachedGeometry.CreateFill(geom)); } } return(null); }