/// <summary> /// Pushes the given matrix onto the transform stack. /// </summary> /// <param name="matrix">The matrix to push.</param> /// <remarks> /// This method also applies the matrix to the graphics context and the current local clip. /// The new local clip is then pushed onto the local clip stack. /// </remarks> public virtual void PushMatrix(PMatrix matrix) { if (matrix == null) return; RectangleF newLocalClip = matrix.InverseTransform(LocalClip); transformStack.Push(graphics.Transform); localClipStack.Push(newLocalClip); graphics.MultiplyTransform(matrix.MatrixReference); }
/// <summary> /// Creates an exact copy of this <see cref="PMatrix"/> object. /// </summary> /// <returns>The <see cref="PMatrix"/> object that his method creates.</returns> public virtual Object Clone() { PMatrix r = new PMatrix(); r.Multiply(this); return(r); }
/// <summary> /// Pops a matrix from the matrix stack. /// </summary> /// <param name="aMatrix">The matrix to pop.</param> public virtual void PopMatrix(PMatrix aMatrix) { matrixStack.Pop(); if (aMatrix != null) { pickBoundsStack.Pop(); } }
/// <summary> /// Pushes the given matrix onto the matrix stack. /// </summary> /// <param name="aMatrix">The matrix to push.</param> public virtual void PushMatrix(PMatrix aMatrix) { matrixStack.Push(new PTuple(PickedNode, aMatrix)); if (aMatrix != null) { RectangleF newPickBounds = aMatrix.InverseTransform(PickBounds); pickBoundsStack.Push(newPickBounds); } }
/// <summary> /// Returns the product of the matrices from the top-most ancestor node (the last node /// in the list) to the given node. /// </summary> /// <param name="nodeOnPath"> /// The bottom-most node in the path for which the matrix product will be computed. /// </param> /// <returns> /// The product of the matrices from the top-most node to the given node. /// </returns> public virtual PMatrix GetPathTransformTo(PNode nodeOnPath) { PMatrix aMatrix = new PMatrix(); object[] matrices = matrixStack.ToArray(); int count = matrices.Length; for (int i = count - 1; i >= 0; i--) { PTuple each = (PTuple)matrices[i]; if (each.matrix != null) { aMatrix.Multiply(each.matrix); } if (nodeOnPath == each.node) { return(aMatrix); } } return(aMatrix); }
protected virtual PActivity AnimateCameraViewMatrixTo(PCamera aCamera, PMatrix aMatrix, int duration) { bool wasOldAnimation = false; // first stop any old animations. if (navigationActivity != null) { navigationActivity.Terminate(); wasOldAnimation = true; } if (duration == 0) { aCamera.ViewMatrix = aMatrix; return null; } PMatrix source = aCamera.ViewMatrixReference; if (!source.MatrixReference.Equals(aMatrix.MatrixReference)) { navigationActivity = aCamera.AnimateViewToMatrix(aMatrix, duration); ((PTransformActivity)navigationActivity).SlowInSlowOut = !wasOldAnimation; return navigationActivity; } return null; }
public void Clear() { Matrix = new PMatrix(); RemoveAllChildren(); CollapseOrderCollection.Clear(); RepresentationCollection.Clear(); CollapsedColumns.Clear(); }
/// <summary> /// Creates a new PTuple that associates the given node witht he given matrix. /// </summary> /// <param name="n">The node to associate with the matrix.</param> /// <param name="m">The matrix to associate with the node.</param> public PTuple(PNode n, PMatrix m) { node = n; matrix = m; }
/// <summary> /// Sets the temp region to the transformed path, widening the path if /// requested to do so. /// </summary> private void SetTempRegion(GraphicsPath path, PMatrix matrix, bool widen) { m_tempPath.Reset(); if (path.PointCount > 0) { m_tempPath.AddPath(path, false); if (widen) { m_tempPath.Widen(m_pen, matrix.MatrixReference); } else { m_tempPath.Transform(matrix.MatrixReference); } } m_tempRegion.MakeInfinite(); m_tempRegion.Intersect(m_tempPath); }
/// <summary> /// Transform this node's matrix by the given matrix. /// </summary> /// <param name="matrix">The transform to apply.</param> public virtual void TransformBy(PMatrix matrix) { this.matrix.Multiply(matrix); InvalidatePaint(); InvalidateFullBounds(); FirePropertyChangedEvent(PROPERTY_KEY_TRANSFORM, PROPERTY_CODE_TRANSFORM, null, matrix); }
/// <summary> /// Overridden. See <see cref="PPaintContext.PushMatrix">PPaintContext.PushTransform</see>. /// </summary> public override void PushMatrix(PMatrix matrix) { if (matrix == null) return; RectangleF newLocalClip = matrix.InverseTransform(LocalClip); localClipStack.Push(newLocalClip); PMatrix newMatrix = (PMatrix)Transform.Clone(); newMatrix.Multiply(matrix); transformStack.Push(newMatrix); SetWorldMatrix(newMatrix); }
public override void SetViewPosition(float x, float y) { if (camera != null) { // If a scroll is in progress - we ignore new scrolls - // if we didn't, since the scrollbars depend on the camera location // we can end up with an infinite loo if (!scrollInProgress) { scrollInProgress = true; // Get the union of all the layers' bounds RectangleF layerBounds = camera.UnionOfLayerFullBounds; PMatrix matrix = camera.ViewMatrix; layerBounds = matrix.Transform(layerBounds); // Union the camera view bounds RectangleF viewBounds = camera.Bounds; layerBounds = RectangleF.Union(layerBounds, viewBounds); // Now find the new view position in view coordinates - // This is basically the distance from the lower right // corner of the window to the upper left corner of the // document // We then measure the offset from the lower right corner // of the document PointF newPoint = new PointF( layerBounds.X + layerBounds.Width - (x + viewBounds.Width), layerBounds.Y + layerBounds.Height - (y + viewBounds.Height)); // Now transform the new view position into global coords newPoint = camera.LocalToView(newPoint); // Compute the new matrix values to put the camera at the // correct location float[] elements = matrix.Elements; elements[4] = - (elements[0] * newPoint.X + elements[1] * newPoint.Y); elements[5] = - (elements[2] * newPoint.X + elements[3] * newPoint.Y); matrix = new PMatrix(elements[0], elements[1], elements[2], elements[3], elements[4], elements[5]); // Now actually set the camera's transform camera.ViewMatrix = matrix; scrollInProgress = false; } } }
/// <summary> /// Multiplies this <see cref="PMatrix"/> object by the specified <see cref="PMatrix"/> /// object by prepending the specified Matrix. /// </summary> /// <param name="matrix"> /// The <see cref="PMatrix"/> object by which this <see cref="PMatrix"/> object is to be /// multiplied. /// </param> public virtual void Multiply(PMatrix matrix) { this.matrix.Multiply(matrix.MatrixReference); }
/// <summary> /// Returns true if this path intersects the given rectangle. /// </summary> /// <remarks> /// This method first checks if the interior of the path intersects with the rectangle. /// If not, the method then checks if the path bounding the pen stroke intersects with /// the rectangle. If either of these cases are true, this method returns true. /// <para> /// <b>Performance Note</b>: For some paths, this method can be very slow. This is due /// to the implementation of IsVisible. The problem usually occurs when many lines are /// joined at very steep angles. See <see cref="PPath">PPath Overview</see> for workarounds. /// </para> /// </remarks> /// <param name="bounds">The rectangle to check for intersection.</param> /// <param name="matrix"> /// A matrix object that specifies a transform to apply to the path and bounds before /// checking for an intersection. /// </param> /// <returns>True if this path intersects the given rectangle; otherwise, false.</returns> public virtual bool Intersects(RectangleF bounds, PMatrix matrix) { if (base.Intersects(bounds)) { // Transform the bounds. if (!matrix.IsIdentity) bounds = matrix.Transform(bounds); // Set the temp region to the transformed path. SetTempRegion(path, matrix, false); if (Brush != null && TEMP_REGION.IsVisible(bounds)) { return true; } else if (pen != null) { // Set the temp region to the transformed, widened path. SetTempRegion(path, matrix, true); return TEMP_REGION.IsVisible(bounds); } } return false; }
protected void CreatePath(Random rnd) { PTransformActivity rotActivity; // Create a path P3Path path = P3Path.CreateEllipse(0, 0, 100, 100); path.Brush = Brushes.Red; path.AddLine(0, 0, 20, 20); path.AddLine(20, 20, 34,67); path.AddArc(0, 30, 30, 30, 30, 30); path.Tolerance = .002f; canvas.Layer.AddChild(path); PMatrix rMatrix = new PMatrix(); PointF center = PUtil.CenterOfRectangle(path.Bounds); rMatrix.RotateBy(90, center.X, center.Y); rotActivity = path.AnimateToMatrix(rMatrix, 2000 + (long)(2000 * rnd.NextDouble())); rotActivity.LoopCount = 1000; rotActivity.Mode = ActivityMode.SourceToDestinationToSource; }
/// <summary> /// Creates an exact copy of this <see cref="PMatrix"/> object. /// </summary> /// <returns>The <see cref="PMatrix"/> object that his method creates.</returns> public virtual Object Clone() { PMatrix r = new PMatrix(); r.Multiply(this); return r; }
/// <summary> /// Get the matrix that will transform the slide to fit in the slide bar. /// </summary> public PMatrix GetUnfocusedMatrix(PNode node, int index) { float scale = 1; if (node.Tag != null) { // Only scale actual slides scale = (slideBar.Height - IMAGE_PADDING) / node.Height; } PMatrix matrix = new PMatrix(); float maxSpacePerSlide = (Width - (node.Width * scale)) / (slides.Count - 1); matrix.Scale = scale; matrix.OffsetX = index * maxSpacePerSlide; matrix.OffsetY = IMAGE_PADDING; return matrix; }
// Get the matrix that will transform the node to fill the main pane. public PMatrix GetFocusedMatrix(PNode slide) { float scale; int width = Width; int height = Height; if (SlideBarVisible) { height -= SLIDE_BAR_HEIGHT; } if ((width / slide.Width) < (height / slide.Height)) { scale = width / slide.Width; height = (int) (slide.Height * scale); } else { scale = height / slide.Height; width = (int) (slide.Width * scale); } PMatrix matrix = new PMatrix(); matrix.Scale = scale; matrix.OffsetX = (Width - width) / 2; if (SlideBarVisible) { matrix.OffsetY = - (Height - SLIDE_BAR_HEIGHT); } else { matrix.OffsetY = - (Height); } return matrix; }
/// <summary> /// Constructs a new PTransformActivity that will animate from the source matrix /// to the destination matrix. /// </summary> /// <param name="duration">The length of one loop of the activity.</param> /// <param name="stepInterval"> /// The minimum number of milliseconds that this activity should delay between /// steps. /// </param> /// <param name="aTarget"> /// The object that the activity will be applied to and where the source /// state will be taken from. /// </param> /// <param name="aDestination">The destination matrix.</param> public PTransformActivity(long duration, long stepInterval, Target aTarget, PMatrix aDestination) : this(duration, stepInterval, 1, ActivityMode.SourceToDestination, aTarget, aDestination) { }
/// <summary> /// This copies the behavior of the standard /// <see cref="PCamera.AnimateViewToMatrix">AnimateViewToMatrix</see> but clears the cache /// when it is done. /// </summary> /// <param name="destination">The final matrix value.</param> /// <param name="duration">The amount of time that the animation should take.</param> /// <returns> /// The newly scheduled activity, if the duration is greater than 0; else null. /// </returns> protected PTransformActivity AnimateStaticViewToTransformFast(PMatrix destination, long duration) { if (duration == 0) { this.ViewMatrix = destination; return null; } PTransformActivity ta = new FastTransformActivity(this, duration, PUtil.DEFAULT_ACTIVITY_STEP_RATE, new PCamera.PCameraTransformTarget(this), destination); PRoot r = Root; if (r != null) { r.ActivityScheduler.AddActivity(ta); } return ta; }
/// <summary> /// Constructs a new PTransformActivity that animate between the source and destination /// matrices in the order specified by the mode, looping the given number of iterations. /// </summary> /// <param name="duration">The length of one loop of the activity.</param> /// <param name="stepInterval"> /// The minimum number of milliseconds that this activity should delay between steps. /// </param> /// <param name="loopCount"> /// The number of times the activity should reschedule itself. /// </param> /// <param name="mode"> /// Defines how the activity interpolates between states. /// </param> /// <param name="aTarget"> /// The object that the activity will be applied to and where the source /// state will be taken from. /// </param> /// <param name="aDestination">The destination matrix.</param> public PTransformActivity(long duration, long stepInterval, int loopCount, ActivityMode mode, Target aTarget, PMatrix aDestination) : base(duration, stepInterval, loopCount, mode) { source = new float[6]; destination = new float[6]; target = aTarget; if (aDestination != null) { destination = aDestination.MatrixReference.Elements; } }
public FastTransformActivity(PCacheCamera target, long duration, long stepInterval, Target aTarget, PMatrix aDestination) : base(duration, stepInterval, 1, ActivityMode.SourceToDestination, aTarget, aDestination) { this.target = target; }
/// <summary> /// Sets the temp region to the transformed path, widening the path if /// requested to do so. /// </summary> private void SetTempRegion(GraphicsPath path, PMatrix matrix, bool widen) { TEMP_PATH.Reset(); if (path.PointCount > 0) { TEMP_PATH.AddPath(path, false); if (widen) { TEMP_PATH.Widen(pen, matrix.MatrixReference); } else { TEMP_PATH.Transform(matrix.MatrixReference); } } TEMP_REGION.MakeInfinite(); TEMP_REGION.Intersect(TEMP_PATH); }
/// <summary> /// Constructs a new PNode. /// </summary> /// <Remarks> /// By default a node's brush is null, and bounds are empty. These values /// must be set for the node to show up on the screen once it's added to /// a scene graph. /// </Remarks> public PNode() { bounds = RectangleF.Empty; fullBoundsCache = RectangleF.Empty; pickable = true; childrenPickable = true; matrix = new PMatrix(); handlers = new EventHandlerList(); Visible = true; }
/// <summary> /// Sets the world transform of the device. /// </summary> /// <param name="matrix"></param> protected virtual void SetWorldMatrix(PMatrix matrix) { float[] piccoloMatrixElements = matrix.Elements; Matrix worldMatrix = new Matrix(); worldMatrix.M11 = piccoloMatrixElements[0]; worldMatrix.M12 = piccoloMatrixElements[1]; worldMatrix.M21 = piccoloMatrixElements[2]; worldMatrix.M22 = piccoloMatrixElements[3]; worldMatrix.M41 = piccoloMatrixElements[4]; worldMatrix.M42 = piccoloMatrixElements[5]; worldMatrix.M33 = 1; worldMatrix.M44 = 1; device.Transform.World = worldMatrix; }
/// <summary> /// Animate this node's matrix from its current values when the activity /// starts to the new values specified in the given matrix. /// </summary> /// <param name="destMatrix">The final matrix value.</param> /// <param name="duration">The amount of time that the animation should take.</param> /// <returns>The newly scheduled activity</returns> /// <remarks> /// If this node descends from the root then the activity will be scheduled, /// else the returned activity should be scheduled manually. If two different /// transform activities are scheduled for the same node at the same time, /// they will both be applied to the node, but the last one scheduled will be /// applied last on each frame, so it will appear to have replaced the /// original. Generally you will not want to do that. /// </remarks> public virtual PTransformActivity AnimateToMatrix(PMatrix destMatrix, long duration) { if (duration == 0) { Matrix = destMatrix; return null; } PTransformActivity.Target t = new PNodeTransformTarget(this); PTransformActivity ta = new PTransformActivity(duration, PUtil.DEFAULT_ACTIVITY_STEP_RATE, t, destMatrix); AddActivity(ta); return ta; }
/// <summary> /// Returns true if this path intersects the given rectangle. /// </summary> /// <remarks> /// This method first checks if the interior of the path intersects with the rectangle. /// If not, the method then checks if the path bounding the pen stroke intersects with /// the rectangle. If either of these cases are true, this method returns true. /// <para> /// <b>Performance Note</b>: For some paths, this method can be very slow. This is due /// to the implementation of IsVisible. The problem usually occurs when many lines are /// joined at very steep angles. /// </para> /// </remarks> /// <param name="bounds">The rectangle to check for intersection.</param> /// <returns>True if this path intersects the given rectangle; otherwise, false.</returns> public override bool Intersects(RectangleF bounds) { // Call intersects with the identity matrix. PMatrix matrix = new PMatrix(); bool isIntersects = false; if (base.Intersects(bounds)) { // Transform the bounds. if (!matrix.IsIdentity) bounds = matrix.Transform(bounds); // Set the temp region to the transformed path. SetTempRegion(m_path, matrix, false); if (Brush != null && m_tempRegion.IsVisible(bounds)) { isIntersects = true; } else if (m_pen != null) { // Set the temp region to the transformed, widened path. SetTempRegion(m_path, matrix, true); isIntersects = m_tempRegion.IsVisible(bounds); } } return isIntersects; }
/// <summary> /// Returns the product of the matrices from the top-most ancestor node (the last node /// in the list) to the given node. /// </summary> /// <param name="nodeOnPath"> /// The bottom-most node in the path for which the matrix product will be computed. /// </param> /// <returns> /// The product of the matrices from the top-most node to the given node. /// </returns> public virtual PMatrix GetPathTransformTo(PNode nodeOnPath) { PMatrix aMatrix = new PMatrix(); object[] matrices = matrixStack.ToArray(); int count = matrices.Length; for (int i = count - 1; i >= 0; i--) { PTuple each = (PTuple) matrices[i]; if (each.matrix != null) aMatrix.Multiply(each.matrix); if (nodeOnPath == each.node) { return aMatrix; } } return aMatrix; }
/// <summary> /// Animate this node's matrix to one that will make this node appear at the specified /// position relative to the specified bounding box. /// </summary> /// <param name="srcPt"></param> /// <param name="destPt"></param> /// <param name="destBounds"></param> /// <param name="millis"></param> /// <remarks> /// The source point specifies a point in the unit square (0, 0) - (1, 1) that /// represents an anchor point on the corresponding node to this matrox. The /// destination point specifies an anchor point on the reference node. The /// position method then computes the matrix that results in transforming this /// node so that the source anchor point coincides with the reference anchor /// point. This can be useful for layout algorithms as it is straightforward to /// position one object relative to another. /// <para> /// For example, If you have two nodes, A and B, and you call /// <code> /// PointF srcPt = new PointF(1.0f, 0.0f); /// PointF destPt = new PointF(0.0f, 0.0f); /// A.Position(srcPt, destPt, B.GlobalBounds, 750); /// </code> /// The result is that A will move so that its upper-right corner is at /// the same place as the upper-left corner of B, and the transition will /// be smoothly animated over a period of 750 milliseconds. /// </para> /// </remarks> public virtual void Position(PointF srcPt, PointF destPt, RectangleF destBounds, int millis) { float srcx, srcy; float destx, desty; float dx, dy; PointF pt1, pt2; if (parent != null) { // First compute translation amount in global coordinates RectangleF srcBounds = GlobalFullBounds; srcx = Lerp(srcPt.X, srcBounds.X, srcBounds.X + srcBounds.Width); srcy = Lerp(srcPt.Y, srcBounds.Y, srcBounds.Y + srcBounds.Height); destx = Lerp(destPt.X, destBounds.X, destBounds.X + destBounds.Width); desty = Lerp(destPt.Y, destBounds.Y, destBounds.Y + destBounds.Height); // Convert vector to local coordinates pt1 = new PointF(srcx, srcy); pt1 = GlobalToLocal(pt1); pt2 = new PointF(destx, desty); pt2 = GlobalToLocal(pt2); dx = (pt2.X - pt1.X); dy = (pt2.Y - pt1.Y); // Finally, animate change PMatrix matrix = new PMatrix(MatrixReference.MatrixReference); matrix.TranslateBy(dx, dy); AnimateToMatrix(matrix, millis); } }
protected void CreateRects(Random rnd) { PTransformActivity rotActivity; P3Path rect; // Create a bunch of animated rectangles for (int x=0; x<2000; x += 100) { for (int y=200; y<1500; y += 100) { int w = 200; int h = 200; rect = P3Path.CreateRectangle(x, y, w, h); rect.Brush = new SolidBrush(Color.FromArgb(50, Color.Purple.R, Color.Purple.G, Color.Purple.B)); rect.Pen = new Pen(Color.Red, 0); canvas.Layer.AddChild(rect); PMatrix matrix = new PMatrix(); matrix.RotateBy(90, x+w/2, y+h/2); rotActivity = rect.AnimateToMatrix(matrix, 5000 + (long)(2000 * rnd.NextDouble())); rotActivity.LoopCount = 1000; rotActivity.Mode = ActivityMode.SourceToDestinationToSource; } } }
/// <summary> /// Animate this node from it's current matrix when the activity starts a new matrix that will fit /// the node into the given bounds. /// </summary> /// <param name="x">The x coordinate of the target bounds.</param> /// <param name="y">The y coordinate of the target bounds.</param> /// <param name="width">The width of the target bounds.</param> /// <param name="height">The height of the target bounds.</param> /// <param name="duration">The amount of time that the animation should take.</param> /// <returns>The newly scheduled activity.</returns> /// <remarks> /// If this node descends from the root then the activity will be scheduled, /// else the returned activity should be scheduled manually. If two different /// transform activities are scheduled for the same node at the same time, /// they will both be applied to the node, but the last one scheduled will be /// applied last on each frame, so it will appear to have replaced the original. /// Generally you will not want to do that. Note this method animates the node's /// matrix, but does not directly change the node's bounds rectangle. Use /// <see cref="AnimateToBounds">AnimateToBounds</see> to animate the node's bounds /// rectangle instead. /// </remarks> public PTransformActivity AnimateMatrixToBounds(float x, float y, float width, float height, long duration) { PMatrix m = new PMatrix(); m.ScaleBy(width / Width, height / Height); float scale = m.Scale; m.OffsetX = x-(X*scale); m.OffsetY = y-(Y*scale); return AnimateToMatrix(m, duration); }
/// <summary> /// Overridden. See <see cref="PNode.Paint">PNode.Paint</see>. /// </summary> protected override void Paint(PPaintContext paintContext) { base.Paint (paintContext); Graphics g = paintContext.Graphics; PMatrix matrix = new PMatrix(g.Transform); RectangleF transRectF = matrix.Transform(bounds); Rectangle transRect = new Rectangle((int)transRectF.X, (int)transRectF.Y, (int)transRectF.Width, (int)transRectF.Height); // Draw the image if the control node is not in editing mode or // if the control is being rendered in a view other than the one // that owns the control. if (!Editing || control.Bounds != transRect || paintContext.Canvas != currentCanvas) { if (Image != null) g.DrawImage(Image, bounds); } }