Top Banner

of 56

Src Core CSharp MS Internal Media3D GeneralTransform2Dto3Dto2D.csharp

Jun 03, 2018

Download

Documents

cilango1
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
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 };

    }

    }