void update_from_endpoints(Vector2d p0, Vector2d p1) { Center = 0.5 * (p0 + p1); Direction = p1 - p0; Extent = 0.5 * Direction.Normalize(); }
public Segment2d(Vector2d center, Vector2d direction, double extent) { Center = center; Direction = direction; Extent = extent; }
public double Project(Vector2d p) { return((p - Center).Dot(Direction)); }
public double Distance(Vector2d pt) { double d = Center.Distance(pt); return(Math.Abs(d - Radius)); }
public void Transform(ITransform2 xform) { Center = xform.TransformP(Center); Radius = xform.TransformScalar(Radius); }
public void Simplify(double clusterTol = 0.0001, double lineDeviationTol = 0.01, bool bSimplifyStraightLines = true) { int n = vertices.Count; if (n < 3) { return; } int i, k, pv; // misc counters Vector2d[] vt = new Vector2d[n + 1]; // vertex buffer bool[] mk = new bool[n + 1]; for (i = 0; i < n + 1; ++i) // marker buffer { mk[i] = false; } // STAGE 1. Vertex Reduction within tolerance of prior vertex cluster double clusterTol2 = clusterTol * clusterTol; vt[0] = vertices[0]; // start at the beginning for (i = 1, k = 1, pv = 0; i < n; i++) { if ((vertices[i] - vertices[pv]).LengthSquared < clusterTol2) { continue; } vt[k++] = vertices[i]; pv = i; } bool skip_dp = false; if (k == 1) { vt[k++] = vertices[1]; vt[k++] = vertices[2]; skip_dp = true; } else if (k == 2) { vt[k++] = vertices[0]; skip_dp = true; } // push on start vertex again, because simplifyDP is for polylines, not polygons vt[k++] = vertices[0]; // STAGE 2. Douglas-Peucker polyline simplification int nv = 0; if (skip_dp == false && lineDeviationTol > 0) { mk[0] = mk[k - 1] = true; // mark the first and last vertices simplifyDP(lineDeviationTol, vt, 0, k - 1, mk); for (i = 0; i < k - 1; ++i) { if (mk[i]) { nv++; } } } else { for (i = 0; i < k; ++i) { mk[i] = true; } nv = k - 1; } // polygon requires at least 3 vertices if (nv == 2) { for (i = 1; i < k - 1; ++i) { if (mk[1] == false) { mk[1] = true; } else if (mk[k - 2] == false) { mk[k - 2] = true; } } nv++; } else if (nv == 1) { mk[1] = true; mk[2] = true; nv += 2; } // copy marked vertices back to this polygon vertices = new List <Vector2d>(); for (i = 0; i < k - 1; ++i) // last vtx is copy of first, and definitely marked { if (mk[i]) { vertices.Add(vt[i]); } } Timestamp++; return; }
public double SignedDistance(Vector2d pt) { double d = Center.Distance(pt); return(d - Radius); }
public Vector3d(Vector2d copy, double _z) { x = copy.x; y = copy.y; z = _z; }
public bool IsReversed; // use ccw orientation instead of cw public Circle2d(Vector2d center, double radius) { IsReversed = false; Center = center; Radius = radius; }
override public MeshGenerator Generate() { if (Polygon == null) { Polygon = Polygon2d.MakeCircle(1.0f, 8); } int Slices = Polygon.VertexCount; int nRings = Vertices.Count; int nRingSize = (NoSharedVertices) ? Slices + 1 : Slices; int nCapVertices = (NoSharedVertices) ? Slices + 1 : 1; if (Capped == false) { nCapVertices = 0; } vertices = new VectorArray3d(nRings * nRingSize + 2 * nCapVertices); uv = new VectorArray2f(vertices.Count); normals = new VectorArray3f(vertices.Count); int nSpanTris = (Vertices.Count - 1) * (2 * Slices); int nCapTris = (Capped) ? 2 * Slices : 0; triangles = new IndexArray3i(nSpanTris + nCapTris); Frame3f fCur = new Frame3f(Frame); Vector3d dv = CurveUtils.GetTangent(Vertices, 0);; fCur.Origin = (Vector3f)Vertices[0]; fCur.AlignAxis(2, (Vector3f)dv); Frame3f fStart = new Frame3f(fCur); // generate tube for (int ri = 0; ri < nRings; ++ri) { // propagate frame if (ri != 0) { Vector3d tan = CurveUtils.GetTangent(Vertices, ri); fCur.Origin = (Vector3f)Vertices[ri]; if (ri == 11) { dv = tan; } fCur.AlignAxis(2, (Vector3f)tan); } float uv_along = (float)ri / (float)(nRings - 1); // generate vertices int nStartR = ri * nRingSize; for (int j = 0; j < nRingSize; ++j) { float uv_around = (float)j / (float)(nRings); int k = nStartR + j; Vector2d pv = Polygon.Vertices[j % Slices]; Vector3d v = fCur.FromPlaneUV((Vector2f)pv, 2); vertices[k] = v; uv[k] = new Vector2f(uv_along, uv_around); Vector3f n = (Vector3f)(v - fCur.Origin).Normalized; normals[k] = n; } } // generate triangles int ti = 0; for (int ri = 0; ri < nRings - 1; ++ri) { int r0 = ri * nRingSize; int r1 = r0 + nRingSize; for (int k = 0; k < nRingSize - 1; ++k) { triangles.Set(ti++, r0 + k, r0 + k + 1, r1 + k + 1, Clockwise); triangles.Set(ti++, r0 + k, r1 + k + 1, r1 + k, Clockwise); } if (NoSharedVertices == false) // close disc if we went all the way { triangles.Set(ti++, r1 - 1, r0, r1, Clockwise); triangles.Set(ti++, r1 - 1, r1, r1 + nRingSize - 1, Clockwise); } } if (Capped) { // add endcap verts int nBottomC = nRings * nRingSize; vertices[nBottomC] = fStart.Origin; uv[nBottomC] = new Vector2f(0.5f, 0.5f); normals[nBottomC] = -fStart.Z; startCapCenterIndex = nBottomC; int nTopC = nBottomC + 1; vertices[nTopC] = fCur.Origin; uv[nTopC] = new Vector2f(0.5f, 0.5f); normals[nTopC] = fCur.Z; endCapCenterIndex = nTopC; if (NoSharedVertices) { // duplicate first loop and make a fan w/ bottom-center int nExistingB = 0; int nStartB = nTopC + 1; for (int k = 0; k < Slices; ++k) { vertices[nStartB + k] = vertices[nExistingB + k]; uv[nStartB + k] = (Vector2f)Polygon.Vertices[k].Normalized; normals[nStartB + k] = normals[nBottomC]; } append_disc(Slices, nBottomC, nStartB, true, Clockwise, ref ti); // duplicate second loop and make fan int nExistingT = nRingSize * (nRings - 1); int nStartT = nStartB + Slices; for (int k = 0; k < Slices; ++k) { vertices[nStartT + k] = vertices[nExistingT + k]; uv[nStartT + k] = (Vector2f)Polygon.Vertices[k].Normalized; normals[nStartT + k] = normals[nTopC]; } append_disc(Slices, nTopC, nStartT, true, !Clockwise, ref ti); } else { append_disc(Slices, nBottomC, 0, true, Clockwise, ref ti); append_disc(Slices, nTopC, nRingSize * (nRings - 1), true, !Clockwise, ref ti); } } return(this); }
public Ray2d(Vector2d origin, Vector2d direction) { this.Origin = origin; this.Direction = direction; this.Direction.Normalize(); // float cast may not be normalized in double, is trouble in algorithms! }
/// <summary> /// hex-grid tiling of circles inside bounds, with spacing between elements /// Returns list of translations to element. /// Always allows at least one row and column, even if element overflows bounds in that dimension. /// </summary> public static List <Vector2d> BoundedCircleTiling2(AxisAlignedBox2d element, AxisAlignedBox2d bounds, double spacing) { Vector2d oshift = -element.Min; double w = element.Width; double h = element.Height; if (MathUtil.EpsilonEqual(w, h, MathUtil.Epsilonf) == false) { throw new Exception("BoundedHexTiling2: input box is not square"); } // note: this is a circle tiling, not a hex tiling, so even though we are // starting in top-left with a "tip" hex, we don't have to offset down so that tip is inside // the box (circle cuts off) double r = w / 2; Hexagon2d hex = new Hexagon2d(element.Center, r, Hexagon2d.TopModes.Tip); hex.InnerRadius = r; double stepx = hex.HorzSpacing; double stepy = hex.VertSpacing; double spacingy = spacing; double spacingx = spacing; // half-rows on top and bottom add up to full row-height int ny = Math.Max(1, (int)(bounds.Height / stepy)); // reduce count so that we fit w/ spacing double spaceh = (ny - 1) * spacingy; while (ny > 1 && bounds.Height - (stepy * ny + spaceh) < 0) { ny--; } // even rows start at x=0 int nx_even = Math.Max(1, (int)(bounds.Width / stepx)); // reduce count if we spill over w/ spacing double spacew = (nx_even - 1) * spacingx; while (nx_even > 1 && bounds.Width - (stepx * nx_even + spacew) < 0) { nx_even--; } // odd rows have an extra half-step added to left side, // so we may need to reduce count int nx_odd = nx_even; spacew = (nx_odd - 1) * spacingx; if (ny > 0 && (stepx * nx_odd + spacew + stepx * 0.5) > bounds.Width) { nx_odd--; spacew = (nx_odd - 1) * spacingx; } List <Vector2d> translations = new List <Vector2d>(); for (int yi = 0; yi < ny; ++yi) { double dy = yi * stepy + yi * spacingy; // x shift and count are different on odd rows double shiftx = stepx * 0.5; int nx = nx_odd; if (yi % 2 == 0) { shiftx = 0; nx = nx_even; } for (int xi = 0; xi < nx; ++xi) { double dx = shiftx + xi * stepx + xi * spacingx; translations.Add(new Vector2d(dx, dy) + oshift + bounds.Min); } } return(translations); }
public void AppendVertex(Vector2d v) { vertices.Add(v); Timestamp++; }
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++; }
public static double IsLeft(ref Vector2d P0, ref Vector2d P1, ref Vector2d P2) { return(Math.Sign(((P1.x - P0.x) * (P2.y - P0.y) - (P2.x - P0.x) * (P1.y - P0.y)))); }
public bool Contains(Vector2d p) { double d = Center.DistanceSquared(p); return(d <= Radius * Radius); }
/// <summary> /// Compute barycentric coordinates/weights of vPoint inside triangle (V0,V1,V2). /// If point is inside triangle, coords will pe positive and sum to 1. /// ie if result is a, then vPoint = a.x*V0 + a.y*V1 + a.z*V2. /// </summary> public static Vector3d BarycentricCoords(Vector2d vPoint, Vector2d V0, Vector2d V1, Vector2d V2) { Vector2d kV02 = V0 - V2; Vector2d kV12 = V1 - V2; Vector2d kPV2 = vPoint - V2; double fM00 = kV02.Dot(kV02); double fM01 = kV02.Dot(kV12); double fM11 = kV12.Dot(kV12); double fR0 = kV02.Dot(kPV2); double fR1 = kV12.Dot(kPV2); double fDet = fM00 * fM11 - fM01 * fM01; double fInvDet = 1.0 / fDet; double fBary1 = (fM11 * fR0 - fM01 * fR1) * fInvDet; double fBary2 = (fM00 * fR1 - fM01 * fR0) * fInvDet; double fBary3 = 1.0 - fBary1 - fBary2; return(new Vector3d(fBary1, fBary2, fBary3)); }
public double DistanceSquared(Vector2d p) { int seg; double segt; return(DistanceSquared(p, out seg, out segt)); }