static RenderTolerance() { // cache this values - only do the check once isVistaOrNewer = Const.IsVistaOrNewer; isSoftwareRendering = (RenderCapability.Tier == 0); isSquare96Dpi = ((MathEx.AreCloseEnough(Const.DpiX, Const.DpiY)) && (MathEx.AreCloseEnough(Const.DpiX, 96.0))); ResetDefaults(); }
private static Matrix GetConversionToRelative(Point min, Point max) { double width = max.X - min.X; double height = max.Y - min.Y; double scaleX = MathEx.AreCloseEnough(width, 0.0) ? 0.0 : 1.0 / width; double scaleY = MathEx.AreCloseEnough(height, 0.0) ? 0.0 : 1.0 / height; Matrix result = new ScaleTransform(scaleX, scaleY).Value; result.OffsetX = -min.X * scaleX; result.OffsetY = -min.Y * scaleY; return(result); }
private bool CompareStroke(Stroke originalStroke, Stroke currerntStroke) { if (originalStroke.StylusPoints.Count != currerntStroke.StylusPoints.Count) { return(false); } for (int i = 0; i < originalStroke.StylusPoints.Count; i++) { if (!(MathEx.AreCloseEnough((Point)originalStroke.StylusPoints[i], (Point)currerntStroke.StylusPoints[i]))) { return(false); } } return(true); }
public void NormalizeTextureCoordinates() { // Shortcuts for common cases if (MathEx.AreCloseEnough(minUV, new Point())) { if (MathEx.AreCloseEnough(maxUV, new Point()) || MathEx.AreCloseEnough(maxUV, new Point(1, 1))) { // pre-normalized or no UV's return; } } double scaleX = maxUV.X - minUV.X; double scaleY = maxUV.Y - minUV.Y; scaleX = MathEx.AreCloseEnough(scaleX, 0.0) ? 0.0 : 1.0 / scaleX; scaleY = MathEx.AreCloseEnough(scaleY, 0.0) ? 0.0 : 1.0 / scaleY; double offsetX = -minUV.X * scaleX; double offsetY = -minUV.Y * scaleY; foreach (Triangle t in frontFaceTriangles) { t.vertex1.TextureCoordinates.X = offsetX + (t.vertex1.U * scaleX); t.vertex1.TextureCoordinates.Y = offsetY + (t.vertex1.V * scaleY); t.vertex2.TextureCoordinates.X = offsetX + (t.vertex2.U * scaleX); t.vertex2.TextureCoordinates.Y = offsetY + (t.vertex2.V * scaleY); t.vertex3.TextureCoordinates.X = offsetX + (t.vertex3.U * scaleX); t.vertex3.TextureCoordinates.Y = offsetY + (t.vertex3.V * scaleY); } foreach (Triangle t in backFaceTriangles) { t.vertex1.TextureCoordinates.X = offsetX + (t.vertex1.U * scaleX); t.vertex1.TextureCoordinates.Y = offsetY + (t.vertex1.V * scaleY); t.vertex2.TextureCoordinates.X = offsetX + (t.vertex2.U * scaleX); t.vertex2.TextureCoordinates.Y = offsetY + (t.vertex2.V * scaleY); t.vertex3.TextureCoordinates.X = offsetX + (t.vertex3.U * scaleX); t.vertex3.TextureCoordinates.Y = offsetY + (t.vertex3.V * scaleY); } }
private static bool DeepEquals(object obj1, object obj2, bool skipUnimportant) { if (object.ReferenceEquals(obj1, obj2)) { // Shortcut- if they are the same object, return true; return(true); } Type type1 = obj1.GetType(); Type type2 = obj2.GetType(); if (type1 != type2) { return(false); } if (type1 == typeof(string)) { return(obj1.ToString() == obj2.ToString()); } bool equals; TrustedType trustedType = PT.Trust(type1); TrustedPropertyInfo[] properties = trustedType.GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (TrustedPropertyInfo property in properties) { if (skipUnimportant) { // If we don't care about the property (declared by Freezable or its ancestors), skip it! if (IsPropertyDeclaredByAncestorsOf(PT.Untrust(property.DeclaringType), typeof(Freezable)) || IsPropertyDeclaredByAncestorsOf(PT.Untrust(property.DeclaringType), typeof(FrameworkElement))) { continue; } } if (IsPropertyProblematic(property)) { continue; } if (property.Name == "Item") { if (obj1 is IEnumerable) { equals = DeepEquals((IEnumerable)obj1, (IEnumerable)obj2, skipUnimportant); } else { // This is an indexer. We can't really compare it. equals = true; } } else { object value1 = property.GetValue(obj1, null); object value2 = property.GetValue(obj2, null); if (property.PropertyType.IsValueType) { switch (property.PropertyType.Name) { case "Double": equals = MathEx.AreCloseEnough((double)value1, (double)value2); break; case "Point": equals = MathEx.AreCloseEnough((Point)value1, (Point)value2); break; case "Vector": equals = MathEx.AreCloseEnough((Vector)value1, (Vector)value2); break; case "Rect": equals = MathEx.AreCloseEnough((Rect)value1, (Rect)value2); break; case "Matrix": equals = MathEx.AreCloseEnough((Matrix)value1, (Matrix)value2); break; case "Point3D": equals = MathEx.AreCloseEnough((Point3D)value1, (Point3D)value2); break; case "Point4D": equals = MathEx.AreCloseEnough((Point4D)value1, (Point4D)value2); break; case "Quaternion": equals = MathEx.AreCloseEnough((Quaternion)value1, (Quaternion)value2); break; case "Vector3D": equals = MathEx.AreCloseEnough((Vector3D)value1, (Vector3D)value2); break; case "Rect3D": equals = MathEx.AreCloseEnough((Rect3D)value1, (Rect3D)value2); break; case "Matrix3D": equals = MathEx.AreCloseEnough((Matrix3D)value1, (Matrix3D)value2); break; default: equals = object.Equals(value1, value2); break; } } else { equals = DeepEquals(value1, value2, skipUnimportant); } } if (!equals) { return(false); } } return(true); }
/// <summary/> public static bool IsAffine(Matrix3D m) { return(MathEx.AreCloseEnough(m.M14, 0) && MathEx.AreCloseEnough(m.M24, 0) && MathEx.AreCloseEnough(m.M34, 0) && MathEx.AreCloseEnough(m.M44, 1)); }
private Side LineSide(Point3D p1, Point3D p2, double x, double y) { // If the two points are the same, this is not a line, thus (x,y) // cannot be on either side of it. if (MathEx.AreCloseEnough(p1.X, p2.X) && MathEx.AreCloseEnough(p1.Y, p2.Y)) { return(Side.None); } // Account for precision errors along the triangle edges based on // RenderTolerance.PixelToEdgeTolerance value and exit early if we're too close to call. double pixelToEdgeTolerance = RenderTolerance.PixelToEdgeTolerance; //Increase edge tolerance in Vista nonstandard DPI //We *shouldn't* need this at any other time //If the ref-renderer is improved to better handle interior edge AA, this can be removed if (!RenderTolerance.IsSquare96Dpi && Const.IsVistaOrNewer) { pixelToEdgeTolerance *= 3; } // pixelToEdgeTolerance is only used to generate tolerance map. We can be more precise when we determine // if a point is inside a triangle. Use a smaller tolerance for this calculation. // double triangleEdgeTolerance = Math.Min(pixelToEdgeTolerance, RenderTolerance.DefaultPixelToEdgeTolerance); double distanceToLine = MathEx.DistanceFromLine2D(new Point3D(x, y, 0), p1, p2); if (Math.Abs(distanceToLine) < pixelToEdgeTolerance) { // We've just been guaranteed that (x,y) is really close to the line passing through // p1 and p2. // This means that if (x,y) is within the bounds of the line *segment* (p1 and p2 are endpoints) // plus tolerance, then (x,y) must be on the line segment (edge). Rect bounds = new Rect(new Point(p1.X, p1.Y), new Point(p2.X, p2.Y)); if (MathEx.Inflate(bounds, pixelToEdgeTolerance).Contains(new Point(x, y))) { pixelOnEdge = true; } // We don't know which side we're on because we're too close, // so report that we're on whichever side the caller wants us to be. // Any final uncertainty will be decided by the value of "pixelOnEdge." if (Math.Abs(distanceToLine) < triangleEdgeTolerance) { return(Side.Both); } } // Cross product's Z component will be positive if the point is on the left of the line, // and negative if the point is on the right. Zero if the point is on the line. double crossProductZ = (p1.X - x) * (p2.Y - y) - (p1.Y - y) * (p2.X - x); if (MathEx.AreCloseEnough(crossProductZ, 0)) { // For the case where the triangle edge is right over a pixel center // and PixelToEdgeTolerance is too small (e.g. 0), we will test a neighboring pixel. // This case counts as on the edge too pixelOnEdge = true; // The pixel that we test is based on D3D's rendering convention // (this guarantees that we don't render the same edge twice) if (!MathEx.AreCloseEnough(p1.Y, p2.Y)) { return(LineSide(p1, p2, x + 1, y)); } else { return(LineSide(p1, p2, x, y + 1)); } } else if (crossProductZ < 0) { return(Side.Right); } else { return(Side.Left); } }