/// <summary> /// Compute opening angle at vertex vID. /// If not a vertex, or valence != 2, returns invalidValue argument. /// If either edge is degenerate, returns invalidValue argument. /// </summary> public double OpeningAngle(int vID, double invalidValue = double.MaxValue) { if (vertices_refcount.isValid(vID) == false) { return(invalidValue); } List <int> vedges = vertex_edges[vID]; if (vedges.Count != 2) { return(invalidValue); } int nbra = edge_other_v(vedges[0], vID); int nbrb = edge_other_v(vedges[1], vID); Vector2d v = new Vector2d(vertices[2 * vID], vertices[2 * vID + 1]); Vector2d a = new Vector2d(vertices[2 * nbra], vertices[2 * nbra + 1]); Vector2d b = new Vector2d(vertices[2 * nbrb], vertices[2 * nbrb + 1]); a -= v; if (a.Normalize() == 0) { return(invalidValue); } b -= v; if (b.Normalize() == 0) { return(invalidValue); } return(Vector2d.AngleD(a, b)); }
public Segment2d(Vector2d p0, Vector2d p1) { //update_from_endpoints(p0, p1); Center = 0.5 * (p0 + p1); Direction = p1 - p0; Extent = 0.5 * Direction.Normalize(); }
// t in range[0,1] spans ellipse public Vector2d TangentT(double t) { double theta = (IsReversed) ? (1 - t) * AngleEndDeg + (t) * AngleStartDeg : (1 - t) * AngleStartDeg + (t) * AngleEndDeg; theta = theta * MathUtil.Deg2Rad; double cost = Math.Cos(theta); double sint = Math.Sin(theta); // [RMS] adapted this formula from dxf.net. double a = this.Extent.x, b = this.Extent.y; double a1 = a * sint; double b1 = b * cost; double k = a1 * a1 + b1 * b1; double d = Math.Sqrt(k); //double k1 = (-a * b * sint) * d; double ddt = 0.5 * (1 / d) * ((2 * a * a * sint * cost) - (2 * b * b * cost * sint)); //double k2 = ddt * (a * b * cost); double dx = ((-a * b * sint) * d - ddt * (a * b * cost)) / k; double dy = ((a * b * cost) * d - ddt * (a * b * sint)) / k; Vector2d tangent = dx * Axis0 + dy * Axis1; if (IsReversed) { tangent = -tangent; } tangent.Normalize(); return(tangent); }
public Segment2d(Segment2d other) { //update_from_endpoints(p0, p1); Center = 0.5 * (other.P0 + other.P1); Direction = other.P1 - other.P0; Extent = 0.5 * Direction.Normalize(); }
public static double PlaneAngleSignedD(Vector2d vFrom, Vector2d vTo) { vFrom.Normalize(); vTo.Normalize(); double fSign = Math.Sign(vFrom.Cross(vTo)); double fAngle = fSign * Vector2d.AngleD(vFrom, vTo); return(fAngle); }
public void NeighboursV(int iVertex, ref Vector2d v0, ref Vector2d v1, bool bNormalize = false) { int N = vertices.Count; v0 = vertices[(iVertex == 0) ? N - 1 : iVertex - 1] - vertices[iVertex]; v1 = vertices[(iVertex + 1) % N] - vertices[iVertex]; if (bNormalize) { v0.Normalize(); v1.Normalize(); } }
public Vector2d TangentT(double t) { double theta = (IsReversed) ? -t * MathUtil.TwoPI : t * MathUtil.TwoPI; Vector2d tangent = new Vector2d(-Math.Sin(theta), Math.Cos(theta)); if (IsReversed) { tangent = -tangent; } tangent.Normalize(); return(tangent); }
// t in range[0,1] spans ellipse public Vector2d TangentT(double t) { double theta = (IsReversed) ? -t * MathUtil.TwoPI : t * MathUtil.TwoPI; double c = Math.Cos(theta), s = Math.Sin(theta); Vector2d tangent = -Extent.x * s * Axis0 + Extent.y * c * Axis1; if (IsReversed) { tangent = -tangent; } tangent.Normalize(); return(tangent); }
public Vector2d TangentT(double t) { double theta = (IsReversed) ? (1 - t) * AngleEndDeg + (t) * AngleStartDeg : (1 - t) * AngleStartDeg + (t) * AngleEndDeg; theta = theta * MathUtil.Deg2Rad; Vector2d tangent = new Vector2d(-Math.Sin(theta), Math.Cos(theta)); if (IsReversed) { tangent = -tangent; } tangent.Normalize(); return(tangent); }
/// <summary> /// Construct normal at poly vertex by averaging face normals. This is /// equivalent (?) to angle-based normal, ie is local/independent of segment lengths. /// Points "inward" for clockwise polygon, outward for counter-clockwise /// </summary> public Vector2d GetNormal_FaceAvg(int i) { Vector2d next = vertices[(i + 1) % vertices.Count]; Vector2d prev = vertices[i == 0 ? vertices.Count - 1 : i - 1]; next -= vertices[i]; next.Normalize(); prev -= vertices[i]; prev.Normalize(); Vector2d n = (next.Perp - prev.Perp); double len = n.Normalize(); if (len == 0) { return((next + prev).Normalized); // this gives right direction for degenerate angle } else { return(n); } }
public static IntersectionType Classify(Vector2d P0, Vector2d D0, Vector2d P1, Vector2d D1, double dotThreshold, ref Vector2d s) { // Ensure dotThreshold is nonnegative. dotThreshold = Math.Max(dotThreshold, (double)0); // The intersection of two lines is a solution to P0+s0*D0 = P1+s1*D1. // Rewrite this as s0*D0 - s1*D1 = P1 - P0 = Q. If D0.Dot(Perp(D1)) = 0, // the lines are parallel. Additionally, if Q.Dot(Perp(D1)) = 0, the // lines are the same. If D0.Dot(Perp(D1)) is not zero, then // s0 = Q.Dot(Perp(D1))/D0.Dot(Perp(D1)) // produces the point of intersection. Also, // s1 = Q.Dot(Perp(D0))/D0.Dot(Perp(D1)) Vector2d diff = P1 - P0; double D0DotPerpD1 = D0.DotPerp(D1); if (Math.Abs(D0DotPerpD1) > dotThreshold) { // Lines intersect in a single point. double invD0DotPerpD1 = ((double)1) / D0DotPerpD1; double diffDotPerpD0 = diff.DotPerp(D0); double diffDotPerpD1 = diff.DotPerp(D1); s[0] = diffDotPerpD1 * invD0DotPerpD1; s[1] = diffDotPerpD0 * invD0DotPerpD1; return(IntersectionType.Point); } // Lines are parallel. diff.Normalize(); double diffNDotPerpD1 = diff.DotPerp(D1); if (Math.Abs(diffNDotPerpD1) <= dotThreshold) { // Lines are colinear. return(IntersectionType.Line); } // Lines are parallel, but distinct. return(IntersectionType.Empty); }
/// <summary> /// Test if segments intersect. Returns true for parallel-line overlaps. /// Returns same result as IntrSegment2Segment2. /// </summary> public bool Intersects(ref Segment2d seg2, double dotThresh = double.Epsilon, double intervalThresh = 0) { // see IntrLine2Line2 and IntrSegment2Segment2 for details on this code Vector2d diff = seg2.Center - Center; double D0DotPerpD1 = Direction.DotPerp(seg2.Direction); if (Math.Abs(D0DotPerpD1) > dotThresh) { // Lines intersect in a single point. double invD0DotPerpD1 = ((double)1) / D0DotPerpD1; double diffDotPerpD0 = diff.DotPerp(Direction); double diffDotPerpD1 = diff.DotPerp(seg2.Direction); double s = diffDotPerpD1 * invD0DotPerpD1; double s2 = diffDotPerpD0 * invD0DotPerpD1; return(Math.Abs(s) <= (Extent + intervalThresh) && Math.Abs(s2) <= (seg2.Extent + intervalThresh)); } // Lines are parallel. diff.Normalize(); double diffNDotPerpD1 = diff.DotPerp(seg2.Direction); if (Math.Abs(diffNDotPerpD1) <= dotThresh) { // Compute the location of segment1 endpoints relative to segment0. diff = seg2.Center - Center; double t1 = Direction.Dot(diff); double tmin = t1 - seg2.Extent; double tmax = t1 + seg2.Extent; var extents = new Interval1d(-Extent, Extent); if (extents.Overlaps(new Interval1d(tmin, tmax))) { return(true); } return(false); } // lines are parallel but not collinear return(false); }
void update_from_endpoints(Vector2d p0, Vector2d p1) { Center = 0.5 * (p0 + p1); Direction = p1 - p0; Extent = 0.5 * Direction.Normalize(); }
public void Chamfer(double chamfer_dist, double minConvexAngleDeg = 30, double minConcaveAngleDeg = 30) { if (IsClockwise) { throw new Exception("must be ccw?"); } List <Vector2d> NewV = new List <Vector2d>(); int N = Vertices.Count; int iCur = 0; do { Vector2d center = Vertices[iCur]; int iPrev = (iCur == 0) ? N - 1 : iCur - 1; Vector2d prev = Vertices[iPrev]; int iNext = (iCur + 1) % N; Vector2d next = Vertices[iNext]; Vector2d cp = prev - center; double cpdist = cp.Normalize(); Vector2d cn = next - center; double cndist = cn.Normalize(); // if degenerate, skip this vert if (cpdist < MathUtil.ZeroTolerancef || cndist < MathUtil.ZeroTolerancef) { iCur = iNext; continue; } double angle = Vector2d.AngleD(cp, cn); // TODO document what this means sign-wise double sign = cp.Perp.Dot(cn); bool bConcave = (sign > 0); double thresh = (bConcave) ? minConcaveAngleDeg : minConvexAngleDeg; // ok not too sharp if (angle > thresh) { NewV.Add(center); iCur = iNext; continue; } double prev_cut_dist = Math.Min(chamfer_dist, cpdist * 0.5); Vector2d prev_cut = center + prev_cut_dist * cp; double next_cut_dist = Math.Min(chamfer_dist, cndist * 0.5); Vector2d next_cut = center + next_cut_dist * cn; NewV.Add(prev_cut); NewV.Add(next_cut); iCur = iNext; } while (iCur != 0); vertices = NewV; Timestamp++; }