Clipping.cs
上传用户:huazai0421
上传日期:2008-05-30
资源大小:405k
文件大小:6k
源码类别:

SilverLight

开发平台:

C#

  1. // Silver.Globe, version 0.11 for Silverlight 1.1 Alpha
  2. // Copyright © Florian Krüsch (xaml-kru.com)
  3. // xaml-kru.com/silverglobe
  4. // This source is subject to the Microsoft Public License (Ms-PL).
  5. // See http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx.
  6. // All other rights reserved.
  7. using System;
  8. using System.Linq;
  9. using System.Collections.Generic;
  10. namespace SilverGlobe.Math3D
  11. {   
  12.     public static class Clipping
  13.     {
  14.         /// <summary>
  15.         /// Clip a sequence of 3D points against the x/y plane, so that hidden points on the backside
  16.         /// are hidden and lines between visible and invisible points appear correct.
  17.         /// </summary>
  18.         public static Point3D[] ClipPolygon(Point3D[] inputPoints, Double radius, Double clipZ)        
  19.         {
  20.             List<Point3D> clippedPoints = new List<Point3D>();
  21.             
  22.             Int32 len = inputPoints.Length;
  23.             if (len < 3) return new Point3D[0];
  24.             Point3D point, prevPoint;
  25.             Boolean isPointInFront, isPrevPointInFront; 
  26.             
  27.             // find first point that in front of the clipping plane
  28.             point = new Point3D();
  29.             Corner outCorner = Corner.TopLeft, inCorner = Corner.TopLeft;
  30.             int startIndex = -1;
  31.             
  32.             int i = 0;
  33.             foreach (Point3D p in inputPoints)
  34.             {
  35.                 if (p.Z >= clipZ)
  36.                 {
  37.                     startIndex = i;
  38.                     point = p;
  39.                     prevPoint = inputPoints[(i + len -1) % len];                    
  40.                     
  41.                     inCorner = outCorner = p.ToCorner();
  42.                     break;
  43.                 }
  44.                 i++;
  45.             }
  46.             // no point found => return empty list
  47.             if (startIndex == -1) return new Point3D[0];
  48.             // ---------------------------------------------------------------
  49.             
  50.             // set initial values
  51.             isPointInFront = true;
  52.             clippedPoints.Add(point);
  53.             Double sliceRadius = Math.Sqrt(radius * radius - clipZ * clipZ);
  54.             for (i = 1; i <= len; i++)
  55.             {
  56.                 prevPoint = point;
  57.                 isPrevPointInFront = isPointInFront;
  58.                 int index = (startIndex + i) % len;
  59.                 point = inputPoints[index];
  60.                 isPointInFront = point.Z >= clipZ;
  61.                 if (isPointInFront)
  62.                 {
  63.                     if (isPrevPointInFront)
  64.                     {
  65.                         clippedPoints.Add(point);
  66.                     }
  67.                     else
  68.                     {
  69.                         // out -> in 
  70.                         
  71.                         // add intersection point
  72.                         Double f = (clipZ - prevPoint.Z) / (point.Z - prevPoint.Z);
  73.                         Point3D p = prevPoint + (point - prevPoint) * f;
  74.                         p = p.AlignToRadius(sliceRadius);
  75.                         inCorner = p.ToCorner();
  76.                         AddCornerSequence(clippedPoints, outCorner, inCorner, clipZ);
  77.                         clippedPoints.Add(p);
  78.                         clippedPoints.Add(point);                        
  79.                     }
  80.                 }
  81.                 else
  82.                 {                    
  83.                     if (isPrevPointInFront)
  84.                     {
  85.                         // in -> out
  86.                         // add intersection point
  87.                         Double f = (clipZ - prevPoint.Z) / (point.Z - prevPoint.Z);
  88.                         Point3D p = prevPoint + (point - prevPoint) * f;
  89.                         p = p.AlignToRadius(sliceRadius);
  90.                         
  91.                         clippedPoints.Add(p);
  92.                         outCorner = p.ToCorner();
  93.                     }
  94.                 }
  95.             }
  96.             return clippedPoints.ToArray();
  97.         }
  98.         /// <summary>
  99.         /// Project a point to the edge of a slice through the sphere.
  100.         /// </summary>
  101.         private static Point3D AlignToRadius(this Point3D p, Double radius)
  102.         {
  103.             Double angle = Math.Atan2(p.Y, p.X);
  104.             return new Point3D(radius * Math.Cos(angle), radius * Math.Sin(angle), p.Z);
  105.         }
  106.         /// <summary>
  107.         /// Find the shortest connection between two points that are clipped by viewplane.
  108.         /// </summary>
  109.         private static void AddCornerSequence(this ICollection<Point3D> clippedPoints, 
  110.                                               Corner startCorner, Corner endCorner, 
  111.                                               Double z)
  112.         {
  113.             byte a = (byte)startCorner;
  114.             byte b = (byte)endCorner;
  115.             if (b < a) b += 4;
  116.             int d = b - a;
  117.             Corner c;
  118.             switch (d)
  119.             {
  120.                 case 3:
  121.                     clippedPoints.Add(startCorner.ToPoint(z));
  122.                     c = (Corner)((a + 3) % 4);
  123.                     clippedPoints.Add(c.ToPoint(z));
  124.                     break;
  125.                 case 2:
  126.                     // start
  127.                     clippedPoints.Add(startCorner.ToPoint(z));
  128.                     // middle
  129.                     c = b > a ? (Corner)((a + 1) % 4) : (Corner)((a + 3) % 4);
  130.                     clippedPoints.Add(c.ToPoint(z));
  131.                     // end
  132.                     clippedPoints.Add(endCorner.ToPoint(z));
  133.                     break;
  134.                 case 1:
  135.                     clippedPoints.Add(startCorner.ToPoint(z));
  136.                     clippedPoints.Add(endCorner.ToPoint(z));
  137.                     break;
  138.                 case 0:
  139.                     clippedPoints.Add(startCorner.ToPoint(z));
  140.                     break;
  141.             }
  142.         }
  143.     }
  144. }