+ All Categories
Home > Documents > Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

Date post: 03-Jun-2018
Category:
Upload: cilango1
View: 216 times
Download: 0 times
Share this document with a friend

of 56

Transcript
  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    1/56

    File: src\Core\CSharp\MS\Internal\Media3D\GeneralTransform2Dto3Dto2D.cs

    Assembly: PresentationCore

    using MS.Internal;

    using System;

    using System.Collections;

    using System.Collections.Generic;

    using System.ComponentModel;

    using System.ComponentModel.Design.Serialization;

    using System.Diagnostics;

    using System.Globalization;

    using System.Reflection;

    using System.Runtime.InteropServices;

    using System.Security.Permissions;

    using System.Windows;

    using System.Windows.Media.Animation;

    using System.Windows.Media.Composition;

    using System.Windows.Markup;

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    2/56

    using System.Windows.Media;

    using System.Windows.Media.Media3D;

    using MS.Internal.PresentationCore;

    using MS.Internal.Media3D;

    using SR = MS.Internal.PresentationCore.SR;

    using SRID = MS.Internal.PresentationCore.SRID;

    namespace MS.Internal.Media3D

    {

    ///

    /// Helper class that encapsulates return data needed for the

    /// hit test capture methods.

    ///

    internal class HitTestEdge

    {

    ///

    /// Constructs a new hit test edge

    ///

    /// First edge point

    /// Second edge point

    /// Texture coordinate of first edge point

    /// Texture coordinate of second edge point

    public HitTestEdge(Point3D p1,

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    3/56

    Point3D p2,

    Point uv1,

    Point uv2)

    {

    _p1 = p1;

    _p2 = p2;

    _uv1 = uv1;

    _uv2 = uv2;

    }

    ///

    /// Projects the stored 3D points in to 2D.

    ///

    /// The transformation matrix to use

    public void Project(GeneralTransform3DTo2D objectToViewportTransform)

    {

    Point projPoint1 = objectToViewportTransform.Transform(_p1);

    Point projPoint2 = objectToViewportTransform.Transform(_p2);

    _p1Transformed = new Point(projPoint1.X, projPoint1.Y);

    _p2Transformed = new Point(projPoint2.X, projPoint2.Y);

    }

    internal Point3D _p1, _p2;

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    4/56

    internal Point _uv1, _uv2;

    // the transformed Point3D value

    internal Point _p1Transformed, _p2Transformed;

    }

    ///

    /// This transform allows one to go from 2D through 3D and back in to 2D

    ///

    internal class GeneralTransform2DTo3DTo2D : GeneralTransform

    {

    ///

    /// Constructor

    ///

    /// The Visual3D that contains the 2D visual

    /// The visual on the Visual3D

    internal GeneralTransform2DTo3DTo2D(Viewport2DVisual3D visual3D, Visual fromVisual)

    {

    IsInverse = false;

    // get a copy of the geometry information - we store our own model to reuse hit

    // test code on the GeometryModel3D

    _geometry = new MeshGeometry3D();

    _geometry.Positions = visual3D.InternalPositionsCache;

    _geometry.TextureCoordinates = visual3D.InternalTextureCoordinatesCache;

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    5/56

    _geometry.TriangleIndices = visual3D.InternalTriangleIndicesCache;

    _geometry.Freeze();

    Visual visual3Dchild = visual3D.Visual;

    // Special case - Setting CacheMode on V2DV3D causes an internal switch from using a

    VisualBrush

    // to using a BitmapCacheBrush. It also introduces an extra 2D Visual in the Visual tree above

    // the V2DV3D.Visual, but this extra node has no effect on transforms and can safely be ignored.

    // The transform returned will be identical to the one created for calling TransformTo* with

    // the V2DV3D.Visual itself.

    Visual descendentVisual = (fromVisual == visual3Dchild._parent) ? visual3Dchild : fromVisual;

    // get a copy of the size of the visual brush and the rect on the

    // visual that the transform is going to/from

    _visualBrushBounds = visual3Dchild.CalculateSubgraphRenderBoundsOuterSpace();

    _visualBounds = descendentVisual.CalculateSubgraphRenderBoundsInnerSpace();

    // get the transform that will let us go from the fromVisual to its last 2D

    // parent before it reaches the 3D part of the graph (i.e. visual3D.Child)

    GeneralTransformGroup transformGroup = new GeneralTransformGroup();

    transformGroup.Children.Add(descendentVisual.TransformToAncestor(visual3Dchild));

    transformGroup.Children.Add(visual3Dchild.TransformToOuterSpace());

    transformGroup.Freeze();

    _transform2D = transformGroup;

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    6/56

    // store the inverse as well

    _transform2DInverse = (GeneralTransform)_transform2D.Inverse;

    if (_transform2DInverse != null)

    {

    _transform2DInverse.Freeze();

    }

    // make a copy of the camera and other values on the Viewport3D

    Viewport3DVisual viewport3D =

    (Viewport3DVisual)VisualTreeHelper.GetContainingVisual2D(visual3D);

    _camera = viewport3D.Camera;

    if (_camera != null)

    {

    _camera = (Camera)viewport3D.Camera.GetCurrentValueAsFrozen();

    }

    _viewSize = viewport3D.Viewport.Size;

    _boundingRect = viewport3D.ComputeSubgraphBounds3D();

    _objectToViewport = visual3D.TransformToAncestor(viewport3D);

    // if the transform was not possible, it could be null - check before freezing

    if (_objectToViewport != null)

    {

    _objectToViewport.Freeze();

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    7/56

    }

    // store the needed transformations for the various operations

    _worldTransformation = M3DUtil.GetWorldTransformationMatrix(visual3D);

    _validEdgesCache = null;

    }

    internal GeneralTransform2DTo3DTo2D()

    {

    }

    ///

    /// Transforms a point

    ///

    /// input point

    /// output point

    /// false if the point cannot be transformed

    public override bool TryTransform(Point inPoint, out Point result)

    {

    if (IsInverse)

    {

    return TryInverseTransform(inPoint, out result);

    }

    else

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    8/56

    {

    return TryRegularTransform(inPoint, out result);

    }

    }

    ///

    /// Performs the transform that goes from the parent Viewport3DVisual down in to the 2D on 3D

    /// contained within the 3D scene

    ///

    /// input point

    /// output point

    /// false if the point cannot be transformed

    private bool TryInverseTransform(Point inPoint, out Point result)

    {

    // set up the hit test parameters

    double distanceAdjust;

    bool foundIntersection = false;

    if (_camera != null)

    {

    RayHitTestParameters rayHitTestParameters = _camera.RayFromViewportPoint(inPoint,

    _viewSize,

    _boundingRect,

    out distanceAdjust);

    rayHitTestParameters.PushVisualTransform(new MatrixTransform3D(_worldTransformation));

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    9/56

    // perfrom the hit test

    // no back material so we only need to concern ourselves with the front faces

    Point pointHit = new Point();

    _geometry.RayHitTest(rayHitTestParameters, FaceType.Front);

    rayHitTestParameters.RaiseCallback(delegate (HitTestResult rawresult)

    {

    RayHitTestResult rayResult = rawresult as RayHitTestResult;

    if (rayResult != null)

    {

    foundIntersection =

    Viewport2DVisual3D.GetIntersectionInfo(rayResult, out pointHit);

    }

    return HitTestResultBehavior.Stop;

    },

    null,

    HitTestResultBehavior.Continue,

    distanceAdjust);

    // perform capture positioning if we didn't hit anything and something has capture

    if (!foundIntersection)

    {

    foundIntersection = HandleOffMesh(inPoint, out pointHit);

    }

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    10/56

    // compute final point

    result = Viewport2DVisual3D.TextureCoordsToVisualCoords(pointHit, _visualBrushBounds);

    }

    else

    {

    result = new Point();

    }

    return foundIntersection;

    }

    ///

    /// Function to deal with mouse capture when off the mesh.

    ///

    /// The location of the mouse

    /// output point

    private bool HandleOffMesh(Point mousePos, out Point outPoint)

    {

    Point[] visCorners = new Point[4];

    if (_validEdgesCache == null)

    {

    // get the points relative to the parent

    visCorners[0] = _transform2D.Transform(new Point(_visualBounds.Left, _visualBounds.Top));

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    11/56

    visCorners[1] = _transform2D.Transform(new Point(_visualBounds.Right, _visualBounds.Top));

    visCorners[2] = _transform2D.Transform(new Point(_visualBounds.Right,

    _visualBounds.Bottom));

    visCorners[3] = _transform2D.Transform(new Point(_visualBounds.Left,

    _visualBounds.Bottom));

    // get the u,v texture coordinate values of the above points

    Point[] texCoordsOfInterest = new Point[4];

    for (int i = 0; i < visCorners.Length; i++)

    {

    texCoordsOfInterest[i] = Viewport2DVisual3D.VisualCoordsToTextureCoords(visCorners[i],

    _visualBrushBounds);

    }

    // get the edges that map to the given visual

    _validEdgesCache = GrabValidEdges(texCoordsOfInterest);

    }

    // find the closest intersection of the mouse position and the edge list

    return FindClosestIntersection(mousePos, _validEdgesCache, out outPoint);

    }

    ///

    /// Function takes the passed in list of texture coordinate points, and then finds the

    /// visible outline of the rectangle specified by those points and returns it.

    ///

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    12/56

    /// The points specifying the rectangle to search

    for

    /// The edges of that rectangle

    private List GrabValidEdges(Point[] visualTexCoordBounds)

    {

    // our final edge list

    List hitTestEdgeList = new List();

    Dictionary adjInformation = new Dictionary();

    // store some important info in local variables for easier access

    Point3DCollection positions = _geometry.Positions;

    PointCollection textureCoords = _geometry.TextureCoordinates;

    Int32Collection triIndices = _geometry.TriangleIndices;

    // if positions and texture coordinates are null, we can't really find what we need so return

    immediately

    if (positions == null || textureCoords == null)

    {

    return new List();

    }

    // this call actually gets the object to camera transform, but we will invert it later, and because of

    that

    // the local variable is named cameraToObjecTransform.

    Matrix3D cameraToObjectTransform = _worldTransformation * _camera.GetViewMatrix();

    try

    {

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    13/56

    cameraToObjectTransform.Invert();

    }

    catch (InvalidOperationException)

    {

    return new List();

    }

    Point3D camPosObjSpace = cameraToObjectTransform.Transform(new Point3D(0, 0, 0));

    // get the bounding box around the passed in texture coordinates to help

    // with early rejection tests

    Rect bbox = Rect.Empty;

    for (int i = 0; i < visualTexCoordBounds.Length; i++)

    {

    bbox.Union(visualTexCoordBounds[i]);

    }

    // walk through the triangles - and look for the triangles we care about

    Point3D[] triangleVertices = new Point3D[3];

    Point[] triangleTexCoords = new Point[3];

    // switch depending on if the mesh is indexed or not

    if (triIndices == null || triIndices.Count == 0)

    {

    int texCoordCount = textureCoords.Count;

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    14/56

    // in this case we have a non-indexed mesh

    int count = positions.Count;

    count = count - (count % 3);

    for (int i = 0; i < count; i+=3)

    {

    // get the triangle indices

    Rect triBBox = Rect.Empty;

    for (int j = 0; j < 3; j++)

    {

    triangleVertices[j] = positions[i + j];

    if (i + j < texCoordCount)

    {

    triangleTexCoords[j] = textureCoords[i + j];

    }

    else

    {

    // In the case you have less texture coordinates than positions, MIL will set

    // missing ones to be 0,0. We do the same to stay consistent.

    // See CMILMesh3D::CopyTextureCoordinatesFromDoubles

    triangleTexCoords[j] = new Point(0,0);

    }

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    15/56

    triBBox.Union(triangleTexCoords[j]);

    }

    if (bbox.IntersectsWith(triBBox))

    {

    ProcessTriangle(triangleVertices, triangleTexCoords, visualTexCoordBounds,

    hitTestEdgeList, adjInformation, camPosObjSpace);

    }

    }

    }

    else

    {

    // in this case we have an indexed mesh

    int count = triIndices.Count;

    int posLimit = positions.Count;

    int texCoordLimit = textureCoords.Count;

    int[] indices = new int[3];

    for (int i = 2; i < count; i += 3)

    {

    // get the triangle indices

    Rect triBBox = Rect.Empty;

    bool validTextureCoordinates = true;

    bool validPositions = true;

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    16/56

    for (int j = 0; j < 3; j++)

    {

    // subtract 2 to take in to account we start i

    // at the high range of indices

    indices[j] = triIndices[(i-2) + j];

    // if a point or texture coordinate is out of range, end early since this is an error

    if (indices[j] < 0 || indices[j] >= posLimit)

    {

    validPositions = false;

    break;

    }

    if (indices[j] < 0 || indices[j] >= texCoordLimit)

    {

    validTextureCoordinates = false;

    break;

    }

    triangleVertices[j] = positions[indices[j]];

    triangleTexCoords[j] = textureCoords[indices[j]];

    triBBox.Union(triangleTexCoords[j]);

    }

    // if the positions were ever invalid, we stop processing - see MeshGeometry3D

    RayHitTestIndexedList

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    17/56

    // for reasoning

    if (!validPositions)

    {

    break;

    }

    if (validTextureCoordinates && bbox.IntersectsWith(triBBox))

    {

    ProcessTriangle(triangleVertices, triangleTexCoords, visualTexCoordBounds,

    hitTestEdgeList, adjInformation, camPosObjSpace);

    }

    }

    }

    // also handle the case of an edge that doesn't also have a backface - i.e a single plane

    foreach (Edge edge in adjInformation.Keys)

    {

    EdgeInfo ei = adjInformation[edge];

    if (ei._hasFrontFace && ei._numSharing == 1)

    {

    HandleSilhouetteEdge(ei._uv1, ei._uv2,

    edge._start, edge._end,

    visualTexCoordBounds,

    hitTestEdgeList);

    }

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    18/56

    }

    // project all the edges to get at the 2D point of interest

    if (_objectToViewport != null)

    {

    for (int i = 0; i < hitTestEdgeList.Count; i++)

    {

    hitTestEdgeList[i].Project(_objectToViewport);

    }

    }

    else

    {

    hitTestEdgeList = new List();

    }

    return hitTestEdgeList;

    }

    ///

    /// Processes the passed in triangle by checking to see if it is facing the camera and if

    /// so searches to see if the texture coordinate edges intersect it. It also looks

    /// to see if there are any silhouette edges and processes these as well.

    ///

    /// The triangle's vertices

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    19/56

    /// The texture coordinates for those vertices

    /// The texture coordinate edges to intersect

    with

    /// The edge list that results should be placed on

    /// The adjacency information for the mesh

    ///

    private void ProcessTriangle(Point3D[] p,

    Point[] uv,

    Point[] visualTexCoordBounds,

    List edgeList,

    Dictionary adjInformation,

    Point3D camPosObjSpace)

    {

    // calculate the normal of the mesh and the vector from a point on the mesh to the camera

    // for back face removal calculations.

    Vector3D normal = Vector3D.CrossProduct(p[1] - p[0], p[2] - p[0]);

    Vector3D dirToCamera = camPosObjSpace - p[0];

    // ignore any triangles that have a normal of (0,0,0)

    if (!(normal.X == 0 && normal.Y == 0 && normal.Z == 0))

    {

    double dotProd = Vector3D.DotProduct(normal, dirToCamera);

    // if the dot product is > 0 then the triangle is visible, otherwise invisible

    if (dotProd > 0.0)

    {

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    20/56

    // loop over the triangle and update any edge information

    ProcessTriangleEdges(p, uv, visualTexCoordBounds, PolygonSide.FRONT, edgeList,

    adjInformation);

    // intersect the bounds of the visual with the triangle

    ProcessVisualBoundsIntersections(p, uv, visualTexCoordBounds, edgeList);

    }

    else

    {

    ProcessTriangleEdges(p, uv, visualTexCoordBounds, PolygonSide.BACK, edgeList,

    adjInformation);

    }

    }

    }

    ///

    /// Function intersects the edges specified by tc with the texture coordinates

    /// on the passed in triangle. If there are any intersections, the edges

    /// of these intersections are added to the edgelist

    ///

    /// The vertices of the triangle

    /// The texture coordinates for that triangle

    /// The texture coordinate edges to be intersected

    against

    /// The list of edges any intersecte edges should be added to

    private void ProcessVisualBoundsIntersections(Point3D[] p,

    Point[] uv,

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    21/56

    Point[] visualTexCoordBounds,

    List edgeList)

    {

    Debug.Assert(uv.Length == p.Length, "vertices and texture coordinate sizes should match");

    List pointList = new List();

    List uvList = new List();

    // loop over the visual's texture coordinate bounds

    for (int i = 0; i < visualTexCoordBounds.Length; i++)

    {

    Point visEdgeStart = visualTexCoordBounds[i];

    Point visEdgeEnd = visualTexCoordBounds[(i + 1) % visualTexCoordBounds.Length];

    // clear out anything that used to be there

    pointList.Clear();

    uvList.Clear();

    // loop over triangle edges

    bool skipListProcessing = false;

    for (int j = 0; j < uv.Length; j++)

    {

    Point uv1 = uv[j];

    Point uv2 = uv[(j + 1) % uv.Length];

    Point3D p3D1 = p[j];

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    22/56

    Point3D p3D2 = p[(j + 1) % p.Length];

    // initial rejection processing

    if (!((Math.Max(visEdgeStart.X, visEdgeEnd.X) < Math.Min(uv1.X, uv2.X)) ||

    (Math.Min(visEdgeStart.X, visEdgeEnd.X) > Math.Max(uv1.X, uv2.X)) ||

    (Math.Max(visEdgeStart.Y, visEdgeEnd.Y) < Math.Min(uv1.Y, uv2.Y)) ||

    (Math.Min(visEdgeStart.Y, visEdgeEnd.Y) > Math.Max(uv1.Y, uv2.Y))))

    {

    // intersect the two lines

    bool areCoincident = false;

    Vector dir = uv2 - uv1;

    double t = IntersectRayLine(uv1, dir, visEdgeStart, visEdgeEnd, out areCoincident);

    // if they are coincident then we have two intersections and don't need to

    // do anymore processing

    if (areCoincident)

    {

    HandleCoincidentLines(visEdgeStart, visEdgeEnd,

    p3D1, p3D2,

    uv1, uv2, edgeList);

    skipListProcessing = true;

    break;

    }

    else if (t >= 0 && t

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    23/56

    Point intersUV = uv1 + dir * t;

    Point3D intersPoint3D = p3D1 + (p3D2 - p3D1) * t;

    double visEdgeDiff = (visEdgeStart - visEdgeEnd).Length;

    if ((intersUV - visEdgeStart).Length < visEdgeDiff &&

    (intersUV - visEdgeEnd).Length < visEdgeDiff)

    {

    pointList.Add(intersPoint3D);

    uvList.Add(intersUV);

    }

    }

    }

    }

    if (!skipListProcessing)

    {

    if (pointList.Count >= 2)

    {

    edgeList.Add(new HitTestEdge(pointList[0], pointList[1],

    uvList[0], uvList[1]));

    }

    else if (pointList.Count == 1)

    {

    Point3D outputPoint;

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    24/56

    // To avoid an edge cases caused by generating a point extremely

    // close to one of the bound points, we test if both points are inside

    // the bounds to be on the safe side - in the worst case we do

    // extra work or generate a small edge

    if (M3DUtil.IsPointInTriangle(visEdgeStart, uv, p, out outputPoint))

    {

    edgeList.Add(new HitTestEdge(pointList[0], outputPoint,

    uvList[0], visEdgeStart));

    }

    if (M3DUtil.IsPointInTriangle(visEdgeEnd, uv, p, out outputPoint))

    {

    edgeList.Add(new HitTestEdge(pointList[0], outputPoint,

    uvList[0], visEdgeEnd));

    }

    }

    else

    {

    Point3D outputPoint1, outputPoint2;

    if (M3DUtil.IsPointInTriangle(visEdgeStart, uv, p, out outputPoint1) &&

    M3DUtil.IsPointInTriangle(visEdgeEnd, uv, p, out outputPoint2))

    {

    edgeList.Add(new HitTestEdge(outputPoint1, outputPoint2,

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    25/56

    visEdgeStart, visEdgeEnd));

    }

    }

    }

    }

    }

    ///

    /// Handles adding an edge when the two line segments are coincident.

    ///

    /// The texture coordinates of the boundary edge

    /// The texture coordinates of the boundary edge

    /// The 3D coordinate of the triangle edge

    /// The 3D coordinates of the triangle edge

    /// The texture coordinates of the triangle edge

    /// The texture coordinates of the triangle edge

    /// The edge list to add to

    private void HandleCoincidentLines(Point visUV1, Point visUV2,

    Point3D tri3D1, Point3D tri3D2,

    Point triUV1, Point triUV2,

    List edgeList)

    {

    Point minVisUV, maxVisUV;

    Point minTriUV, maxTriUV;

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    26/56

    Point3D minTri3D, maxTri3D;

    // to be used in final edge creation

    Point uv1, uv2;

    Point3D p1, p2;

    // order the points and give refs to them for ease of use

    if (Math.Abs(visUV1.X - visUV2.X) > Math.Abs(visUV1.Y - visUV2.Y))

    {

    if (visUV1.X

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    27/56

    maxTriUV = triUV2;

    maxTri3D = tri3D2;

    }

    else

    {

    minTriUV = triUV2;

    minTri3D = tri3D2;

    maxTriUV = triUV1;

    maxTri3D = tri3D1;

    }

    // now actually create the edge

    // compute the minimum value

    if (minVisUV.X < minTriUV.X)

    {

    uv1 = minTriUV;

    p1 = minTri3D;

    }

    else

    {

    uv1 = minVisUV;

    p1 = minTri3D + (minVisUV.X - minTriUV.X) / (maxTriUV.X - minTriUV.X) * (maxTri3D -

    minTri3D);

    }

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    28/56

    // compute the maximum value

    if (maxVisUV.X > maxTriUV.X)

    {

    uv2 = maxTriUV;

    p2 = maxTri3D;

    }

    else

    {

    uv2 = maxVisUV;

    p2 = minTri3D + (maxVisUV.X - minTriUV.X) / (maxTriUV.X - minTriUV.X) * (maxTri3D -

    minTri3D);

    }

    }

    else

    {

    if (visUV1.Y

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    29/56

    if (triUV1.Y

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    30/56

    {

    uv1 = minVisUV;

    p1 = minTri3D + (minVisUV.Y - minTriUV.Y) / (maxTriUV.Y - minTriUV.Y) * (maxTri3D -

    minTri3D);

    }

    // compute the maximum value

    if (maxVisUV.Y > maxTriUV.Y)

    {

    uv2 = maxTriUV;

    p2 = maxTri3D;

    }

    else

    {

    uv2 = maxVisUV;

    p2 = minTri3D + (maxVisUV.Y - minTriUV.Y) / (maxTriUV.Y - minTriUV.Y) * (maxTri3D -

    minTri3D);

    }

    }

    // add the edge

    edgeList.Add(new HitTestEdge(p1, p2, uv1, uv2));

    }

    ///

    /// Intersects a ray with the line specified by the passed in end points. The parameterized

    coordinate along the ray of

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    31/56

    /// intersection is returned.

    ///

    /// The ray origin

    /// The ray direction

    /// First point of the line to intersect against

    /// Second point of the line to intersect against

    /// Whether the ray and line are coincident

    ///

    /// The parameter along the ray of the point of intersection.

    /// If the ray and line are parallel and not coincident, this will be -1.

    ///

    private double IntersectRayLine(Point o, Vector d, Point p1, Point p2, out bool coinc)

    {

    coinc = false;

    // deltas

    double dy = p2.Y - p1.Y;

    double dx = p2.X - p1.X;

    // handle case of a vertical line

    if (dx == 0)

    {

    if (d.X == 0)

    {

    coinc = (o.X == p1.X);

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    32/56

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    33/56

    }

    ///

    /// Helper structure to represent an edge

    ///

    private struct Edge

    {

    public Edge(Point3D s, Point3D e)

    {

    _start = s;

    _end = e;

    }

    public Point3D _start;

    public Point3D _end;

    }

    ///

    /// Information about an edge such as whether it belongs to a front/back facing

    /// triangle, the texture coordinates for the edge, and how many polygons refer

    /// to that edge.

    ///

    private class EdgeInfo

    {

    public EdgeInfo()

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    34/56

    {

    _hasFrontFace = _hasBackFace = false;

    _numSharing = 0;

    }

    public bool _hasFrontFace;

    public bool _hasBackFace;

    public Point _uv1;

    public Point _uv2;

    public int _numSharing;

    }

    ///

    /// Processes the edges of the given triangle. It does so by updating

    /// the adjacency information based on the direction the polygon is facing.

    /// If there is a silhouette edge found, then this edge is added to the list

    /// of edges if it is within the texture coordinate bounds passed to the function.

    ///

    /// The triangle's vertices

    /// The texture coordinates for those vertices

    /// The texture coordinate edges being searched

    for

    /// Which side the polygon is facing (greateer than 0 front, less than

    0 back)

    /// The list of edges comprosing the visual outline

    /// The adjacency information structure

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    35/56

    private void ProcessTriangleEdges(Point3D[] p,

    Point[] uv,

    Point[] visualTexCoordBounds,

    PolygonSide polygonSide,

    List edgeList,

    Dictionary adjInformation)

    {

    // loop over all the edges and add them to the adjacency list

    for (int i = 0; i < p.Length; i++)

    {

    Point uv1, uv2;

    Point3D p3D1 = p[i];

    Point3D p3D2 = p[(i + 1) % p.Length];

    Edge edge;

    // order the edge points so insertion in to adjInformation is consistent

    if (p3D1.X < p3D2.X ||

    (p3D1.X == p3D2.X && p3D1.Y < p3D2.Y) ||

    (p3D1.X == p3D2.X && p3D1.Y == p3D2.Y && p3D1.Z < p3D1.Z))

    {

    edge = new Edge(p3D1, p3D2);

    uv1 = uv[i];

    uv2 = uv[(i + 1) % p.Length];

    }

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    36/56

    else

    {

    edge = new Edge(p3D2, p3D1);

    uv2 = uv[i];

    uv1 = uv[(i + 1) % p.Length];

    }

    // look up the edge information

    EdgeInfo edgeInfo;

    if (adjInformation.ContainsKey(edge))

    {

    edgeInfo = adjInformation[edge];

    }

    else

    {

    edgeInfo = new EdgeInfo();

    adjInformation[edge] = edgeInfo;

    }

    edgeInfo._numSharing++;

    // whether or not the edge has already been added to the edge list

    bool alreadyAdded = edgeInfo._hasBackFace && edgeInfo._hasFrontFace;

    // add the edge to the info list

    if (polygonSide == PolygonSide.FRONT)

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    37/56

    {

    edgeInfo._hasFrontFace = true;

    edgeInfo._uv1 = uv1;

    edgeInfo._uv2 = uv2;

    }

    else

    {

    edgeInfo._hasBackFace = true;

    }

    // if the sides are different we may need to add an edge

    if (!alreadyAdded && edgeInfo._hasBackFace && edgeInfo._hasFrontFace)

    {

    HandleSilhouetteEdge(edgeInfo._uv1, edgeInfo._uv2,

    edge._start, edge._end,

    visualTexCoordBounds,

    edgeList);

    }

    }

    }

    ///

    /// Handles intersecting a silhouette edge against the passed in texture coordinate

    /// bounds. It behaves similarly to the case of intersection the bounds with a triangle

    /// except the testing order is switched.

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    38/56

    ///

    /// The texture coordinates of the edge

    /// The texture coordinates of the edge

    /// The 3D point of the edge

    /// The 3D point of the edge

    /// The texture coordinate bounds

    /// The list of edges

    private void HandleSilhouetteEdge(Point uv1, Point uv2,

    Point3D p3D1, Point3D p3D2,

    Point[] bounds,

    List edgeList)

    {

    List pointList = new List();

    List uvList = new List();

    Vector dir = uv2 - uv1;

    // loop over object bounds

    for (int i = 0; i < bounds.Length; i++)

    {

    Point visEdgeStart = bounds[i];

    Point visEdgeEnd = bounds[(i + 1) % bounds.Length];

    // initial rejection processing

    if (!((Math.Max(visEdgeStart.X, visEdgeEnd.X) < Math.Min(uv1.X, uv2.X)) ||

    (Math.Min(visEdgeStart.X, visEdgeEnd.X) > Math.Max(uv1.X, uv2.X)) ||

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    39/56

    (Math.Max(visEdgeStart.Y, visEdgeEnd.Y) < Math.Min(uv1.Y, uv2.Y)) ||

    (Math.Min(visEdgeStart.Y, visEdgeEnd.Y) > Math.Max(uv1.Y, uv2.Y))))

    {

    // intersect the two lines

    bool areCoincident = false;

    double t = IntersectRayLine(uv1, dir, visEdgeStart, visEdgeEnd, out areCoincident);

    // silhouette edge processing will only include non-coincident lines

    if (areCoincident)

    {

    // if it's coincident, we'll let the normal processing handle this edge

    return;

    }

    else if (t >= 0 && t

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    40/56

    }

    }

    }

    }

    if (pointList.Count >= 2)

    {

    edgeList.Add(new HitTestEdge(pointList[0], pointList[1],

    uvList[0], uvList[1]));

    }

    else if (pointList.Count == 1)

    {

    // for the case that uv1/2 is actually a point on or extremely close to the bounds

    // of the polygon, we do the pointinpolygon test on both to avoid any numerical

    // precision issues - in the worst case we end up with a very small edge and

    // the right edge

    if (IsPointInPolygon(bounds, uv1))

    {

    edgeList.Add(new HitTestEdge(pointList[0], p3D1,

    uvList[0], uv1));

    }

    if (IsPointInPolygon(bounds, uv2))

    {

    edgeList.Add(new HitTestEdge(pointList[0], p3D2,

    uvList[0], uv2));

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    41/56

    }

    }

    else

    {

    if (IsPointInPolygon(bounds, uv1) &&

    IsPointInPolygon(bounds, uv2))

    {

    edgeList.Add(new HitTestEdge(p3D1, p3D2,

    uv1, uv2));

    }

    }

    }

    ///

    /// Function tests to see whether the point p is contained within the polygon

    /// specified by the list of points passed to the function. p is considered within

    /// this polygon if it is on the same side of all the edges. A point on any of

    /// the edges of the polygon is not considered within the polygon.

    ///

    /// The polygon to test against

    /// The point to be tested against

    /// Whether the point is in the polygon

    private bool IsPointInPolygon(Point[] polygon, Point p)

    {

    bool sign = false;

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    42/56

    for (int i = 0; i < polygon.Length; i++)

    {

    double crossProduct = Vector.CrossProduct(polygon[(i + 1) % polygon.Length] - polygon[i],

    polygon[i] - p);

    bool currSign = crossProduct > 0;

    if (i == 0)

    {

    sign = currSign;

    }

    else

    {

    if (sign != currSign) return false;

    }

    }

    return true;

    }

    ///

    /// Finds the point in edges that is closest ot the mouse position. Updates closestIntersectionInfo

    /// with the results of this calculation

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    43/56

    ///

    /// The mouse position

    /// The edges to test against

    /// The final intersection point

    /// The closest intersection point

    private bool FindClosestIntersection(Point mousePos, List edges, out Point finalPoint)

    {

    bool success = false;

    double closestDistance = Double.MaxValue;

    Point closestIntersection = new Point(); // the uv of the closest intersection

    finalPoint = new Point();

    // Find the closest point to the mouse position

    for (int i=0, count = edges.Count; i < count; i++)

    {

    Vector v1 = mousePos - edges[i]._p1Transformed;

    Vector v2 = edges[i]._p2Transformed - edges[i]._p1Transformed;

    Point currClosest;

    double distance;

    // calculate the distance from the mouse position to this edge

    // The closest distance can be computed by projecting v1 on to v2. If the

    // projectiong occurs between _p1Transformed and _p2Transformed, then this is the

    // closest point. Otherwise, depending on which side it lies, it is either _p1Transformed

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    44/56

    // or _p2Transformed.

    //

    // The projection equation is given as: (v1 DOT v2) / (v2 DOT v2) * v2.

    // v2 DOT v2 will always be positive. Thus, if v1 DOT v2 is negative, we know the projection

    // will occur before _p1Transformed (and so it is the closest point). If (v1 DOT v2) is greater

    // than (v2 DOT v2), then we have gone passed _p2Transformed and so it is the closest point.

    // Otherwise the projection gives us this value.

    //

    double denom = v2 * v2;

    if (denom == 0)

    {

    currClosest = edges[i]._p1Transformed;

    distance = v1.Length;

    }

    else

    {

    double numer = v2 * v1;

    if (numer < 0)

    {

    currClosest = edges[i]._p1Transformed;

    }

    else

    {

    if (numer > denom)

    {

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    45/56

    currClosest = edges[i]._p2Transformed;

    }

    else

    {

    currClosest = edges[i]._p1Transformed + (numer / denom) * v2;

    }

    }

    distance = (mousePos - currClosest).Length;

    }

    // see if we found a new closest distance

    if (distance < closestDistance)

    {

    closestDistance = distance;

    if (denom != 0)

    {

    closestIntersection = ((currClosest - edges[i]._p1Transformed).Length / Math.Sqrt(denom)

    *

    (edges[i]._uv2 - edges[i]._uv1)) + edges[i]._uv1;

    }

    else

    {

    closestIntersection = edges[i]._uv1;

    }

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    46/56

    }

    }

    if (closestDistance != Double.MaxValue)

    {

    Point ptOnVisual = Viewport2DVisual3D.TextureCoordsToVisualCoords(closestIntersection,

    _visualBrushBounds);

    if (_transform2DInverse != null)

    {

    Point ptRelToCapture = _transform2DInverse.Transform(ptOnVisual);

    // we want to "ring" around the outside so things like buttons are not pressed when we

    move off the mesh

    // this code here does that - the +BUFFER_SIZE and -BUFFER_SIZE are to give a bit of a

    // buffer for any numerical issues

    if (ptRelToCapture.X = _visualBounds.Bottom - 1) ptRelToCapture.Y += BUFFER_SIZE;

    Point finalVisualPoint = _transform2D.Transform(ptRelToCapture);

    finalPoint = Viewport2DVisual3D.VisualCoordsToTextureCoords(finalVisualPoint,

    _visualBrushBounds);

    success = true;

    }

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    47/56

    }

    return success;

    }

    ///

    /// Performs the transform that goes from 2D on 3D content contained within the 3D scene

    /// up to the containing Viewport3DVisual

    ///

    /// input point

    /// output point

    /// false if the point cannot be transformed

    private bool TryRegularTransform(Point inPoint, out Point result)

    {

    Point texCoord = Viewport2DVisual3D.VisualCoordsToTextureCoords(inPoint,

    _visualBrushBounds);

    // need to walk the texture coordinates and look for where this point intersects one of them

    Point3D point3D;

    if (_objectToViewport != null &&

    Viewport2DVisual3D.Get3DPointFor2DCoordinate(texCoord,

    out point3D,

    _geometry.Positions,

    _geometry.TextureCoordinates,

    _geometry.TriangleIndices))

    {

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    48/56

    // convert from this 3D point up to the containing Viewport3D

    return _objectToViewport.TryTransform(point3D, out result);

    }

    else

    {

    result = new Point();

    return false;

    }

    }

    ///

    /// Transform the rect bounds into the smallest axis alligned bounding box that

    /// contains all the point in the original bounds.

    ///

    ///

    ///

    public override Rect TransformBounds(Rect rect)

    {

    List edges = null;

    // intersect the rect given to us with the bounds of the visual brush to guarantee the rect we are

    // searching for is within the visual brush

    rect.Intersect(_visualBrushBounds);

    // get the texture coordinate values for the rect's corners

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    49/56

    Point[] texCoordsOfInterest = new Point[4];

    texCoordsOfInterest[0] = Viewport2DVisual3D.VisualCoordsToTextureCoords(rect.TopLeft,

    _visualBrushBounds);

    texCoordsOfInterest[1] = Viewport2DVisual3D.VisualCoordsToTextureCoords(rect.TopRight,

    _visualBrushBounds);

    texCoordsOfInterest[2] = Viewport2DVisual3D.VisualCoordsToTextureCoords(rect.BottomRight,

    _visualBrushBounds);

    texCoordsOfInterest[3] = Viewport2DVisual3D.VisualCoordsToTextureCoords(rect.BottomLeft,

    _visualBrushBounds);

    // get the edges that map to the given rect

    edges = GrabValidEdges(texCoordsOfInterest);

    Rect result = Rect.Empty;

    if (edges != null)

    {

    for (int i = 0, count = edges.Count; i < count; i++)

    {

    result.Union(edges[i]._p1Transformed);

    result.Union(edges[i]._p2Transformed);

    }

    }

    return result;

    }

    ///

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    50/56

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    51/56

    }

    }

    ///

    /// Returns true if the transform is an inverse

    ///

    internal bool IsInverse

    {

    get { return _fInverse; }

    set { _fInverse = value; }

    }

    ///

    /// Implementation of Freezable.CreateInstanceCore.

    ///

    /// The new Freezable.

    protected override Freezable CreateInstanceCore()

    {

    return new GeneralTransform2DTo3DTo2D();

    }

    ///

    /// Implementation of Freezable.CloneCore.

    ///

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    52/56

    ///

    protected override void CloneCore(Freezable sourceFreezable)

    {

    GeneralTransform2DTo3DTo2D transform = (GeneralTransform2DTo3DTo2D)sourceFreezable;

    base.CloneCore(sourceFreezable);

    CopyCommon(transform);

    }

    ///

    /// Implementation of Freezable.CloneCurrentValueCor

    e.

    ///

    ///

    protected override void CloneCurrentValueCore(Freezable sourceFreezable)

    {

    GeneralTransform2DTo3DTo2D transform = (GeneralTransform2DTo3DTo2D)sourceFreezable;

    base.CloneCurrentValueCore(sourceFreezable);

    CopyCommon(transform);

    }

    ///

    /// Implementation of Freezable.GetAsFrozenCore.

    ///

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    53/56

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    54/56

    private void CopyCommon(GeneralTransform2DTo3DTo2D transform)

    {

    _fInverse = transform._fInverse;

    _geometry = transform._geometry;

    _visualBounds = transform._visualBounds;

    _visualBrushBounds = transform._visualBrushBounds;

    _transform2D = transform._transform2D;

    _transform2DInverse = transform._transform2DInverse;

    _camera = transform._camera;

    _viewSize = transform._viewSize;

    _boundingRect = transform._boundingRect;

    _worldTransformation = transform._worldTransformation;

    _objectToViewport = transform._objectToViewport;

    _validEdgesCache = null;

    }

    private bool _fInverse;

    // the geometry of the 3D object

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    55/56

    private MeshGeometry3D _geometry;

    // the size of the visual brush and the visual on it we're interested in

    private Rect _visualBounds;

    private Rect _visualBrushBounds;

    // the transform to go in to and out of the coordinate space fo the visual we're

    // interested in

    private GeneralTransform _transform2D;

    private GeneralTransform _transform2DInverse;

    // the camera being used on the 3D viewport

    private Camera _camera;

    private Size _viewSize;

    private Rect3D _boundingRect;

    // transformations through the 3D scene

    private Matrix3D _worldTransformation;

    private GeneralTransform3DTo2D _objectToViewport;

    // the cache of valid edges

    List _validEdgesCache = null;

    // the "ring" around the element with capture to use in the capture case

    private const double BUFFER_SIZE = 2.0;

  • 8/12/2019 Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

    56/56

    private enum PolygonSide { FRONT, BACK };

    }

    }


Recommended