public void Apply() { Vector3d Origin = BendPlane.Origin; Vector3d BendAxis1 = BendPlane.Z; float sideSign = (BendAngle > 0) ? 1 : -1; MeshVertexSelection vertices = new MeshVertexSelection(Mesh); foreach (int vid in Mesh.VertexIndices()) { Vector3d v = Mesh.GetVertex(vid); float sign = BendPlane.DistanceToPlaneSigned((Vector3f)v, 1); if (sign * sideSign > 0) { vertices.Select(vid); } } Quaterniond rotation = Quaterniond.AxisAngleD(BendPlane.X, -BendAngle); foreach (int vid in vertices) { Vector3d v = Mesh.GetVertex(vid); Vector3d vNew = rotation * (v - Origin) + Origin; Mesh.SetVertex(vid, vNew); } }
public override fMesh MakeGeometry(AxisGizmoFlags widget) { switch (widget) { case AxisGizmoFlags.AxisTranslateY: if (MyAxisTranslateY == null) { Radial3DArrowGenerator arrowGen = new Radial3DArrowGenerator() { HeadLength = 2.0f, TipRadius = 0.1f, StickLength = 1.5f, Clockwise = true }; DMesh3 mesh = arrowGen.Generate().MakeDMesh(); MeshNormals.QuickCompute(mesh); MeshTransforms.Translate(mesh, 0.5 * Vector3d.AxisY); DMesh3 flip = new DMesh3(mesh); MeshTransforms.Rotate(flip, Vector3d.Zero, Quaterniond.AxisAngleD(Vector3d.AxisX, 180)); MeshEditor.Append(mesh, flip); MyAxisTranslateY = new fMesh(mesh); } return(MyAxisTranslateY); default: return(null); } }
public GridDistanceField() { Origin = -100 * Vector3d.One; Rotation = Quaterniond.AxisAngleD(Vector3d.AxisX, 45) * Quaterniond.AxisAngleD(Vector3d.AxisZ, 45); CellSize = 8.0f; Radius = 1.0f; }
void update_hole_mesh() { CappedCylinderGenerator cylgen = new CappedCylinderGenerator() { BaseRadius = 0.5f, TopRadius = 0.5f, Height = 1, Slices = this.subdivisions, Clockwise = true }; DMesh3 mesh = cylgen.Generate().MakeDMesh(); MeshTransforms.Rotate(mesh, Vector3d.Zero, Quaterniond.AxisAngleD(Vector3d.AxisX, 90)); CavityPreviewSO.ReplaceMesh(mesh, true); }
/// <summary> /// Cut through-hole either vertically or horizontally. /// /// One current failure mode is if we get more than two ray-hits, which /// can happen due pathological cases or unexpected mesh shape. Currently /// trying to handle the pathological cases (ie ray hits adjacent triangles cases) /// via sorting, not sure if this works spectacularly well. /// /// </summary> protected bool CutThroughHole(DMesh3 mesh, HoleInfo hi, Vector3d translate) { Vector3d basePoint = CombinedBounds.Center - CombinedBounds.Extents.y * Vector3d.AxisY + translate; // do we need to compute spatial DS for each hole? not super efficient... DMeshAABBTree3 spatial = new DMeshAABBTree3(mesh, true); Vector3d origin = Vector3d.Zero; Vector3d direction = Vector3d.One; if (hi.IsVertical) { direction = Vector3d.AxisY; origin = basePoint + new Vector3d(hi.XZOffset.x, 0, hi.XZOffset.y) - 100 * direction; } else { origin = basePoint + hi.Height * Vector3d.AxisY; direction = Quaterniond.AxisAngleD(Vector3d.AxisY, hi.AroundAngle) * Vector3d.AxisX; } // Find upper and lower triangles that contain center-points of // holes we want to cut. This is the most error-prone part // because we depend on ray-hits, which is not very reliable... Ray3d ray1 = new Ray3d(origin, direction); Ray3d ray2 = new Ray3d(origin + 10000 * direction, -direction); if (hi.GroupIDFilters.a > 0) { spatial.TriangleFilterF = (tid) => { return(mesh.GetTriangleGroup(tid) == hi.GroupIDFilters.a); }; } int hit_1 = spatial.FindNearestHitTriangle(ray1); spatial.TriangleFilterF = null; if (hi.GroupIDFilters.b > 0) { spatial.TriangleFilterF = (tid) => { return(mesh.GetTriangleGroup(tid) == hi.GroupIDFilters.b); }; } int hit_2 = spatial.FindNearestHitTriangle(ray2); spatial.TriangleFilterF = null; if (hit_1 == DMesh3.InvalidID || hit_2 == DMesh3.InvalidID) { return(false); } if (hit_1 == hit_2) { return(false); } List <int> hitTris = new List <int>() { hit_1, hit_2 }; Frame3f projectFrame = new Frame3f(ray1.Origin, ray1.Direction); int nVerts = 32; if (hi.Vertices != 0) { nVerts = hi.Vertices; } double angleShiftRad = hi.AxisAngleD * MathUtil.Deg2Rad; Polygon2d circle = Polygon2d.MakeCircle(hi.Radius, nVerts, angleShiftRad); List <EdgeLoop> edgeLoops = new List <EdgeLoop>(); foreach (int hit_tid in hitTris) { try { MeshInsertProjectedPolygon insert = new MeshInsertProjectedPolygon(mesh, circle, projectFrame, hit_tid) { SimplifyInsertion = true }; if (insert.Insert()) { // if we have extra edges just randomly collapse EdgeLoop loop = insert.InsertedLoop; if (loop.VertexCount > circle.VertexCount) { loop = simplify_loop(mesh, loop, circle.VertexCount); } edgeLoops.Add(loop); } else { f3.DebugUtil.Log("insert.Insert() failed!!"); return(false); } } catch (Exception e) { // ignore this loop but we might already be in trouble... f3.DebugUtil.Log("insert.Insert() threw exception for hole {0}!!", hi.nHole); f3.DebugUtil.Log(e.Message); } } if (edgeLoops.Count != 2) { return(false); } try { MeshEditor editor = new MeshEditor(mesh); EdgeLoop l0 = edgeLoops[0]; EdgeLoop l1 = edgeLoops[1]; l1.Reverse(); editor.StitchVertexLoops_NearestV(l0.Vertices, l1.Vertices); // split edges around the holes we cut. This is helpful // if we are going to do additional operations in these areas, // as it gives us extra rings to work with //MeshEdgeSelection edges = new MeshEdgeSelection(mesh); //edges.SelectVertexEdges(l0.Vertices); //edges.SelectVertexEdges(l1.Vertices); //DMesh3.EdgeSplitInfo splitInfo; //foreach ( int eid in edges ) // mesh.SplitEdge(eid, out splitInfo); return(true); } catch { f3.DebugUtil.Log("stitch threw exception!"); return(false); } }
public static void test_Matrix3d() { { Matrix3d Identity = new Matrix3d(true); for (int r = 0; r < 3; ++r) { for (int c = 0; c < 3; ++c) { Util.gDevAssert((r == c) ? Identity[r, c] == 1 : Identity[r, c] == 0); } } } { double[] buffer = new double[9] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; Matrix3d M = new Matrix3d(buffer); for (int r = 0; r < 3; ++r) { for (int c = 0; c < 3; ++c) { Util.gDevAssert(M[r, c] == buffer[r * 3 + c]); } } for (int k = 0; k < 9; ++k) { Util.gDevAssert(M[k] == buffer[k]); } Matrix3d M2 = new Matrix3d(new Vector3d(1, 2, 3), new Vector3d(4, 5, 6), new Vector3d(7, 8, 9), true); Util.gDevAssert(M.EpsilonEqual(M2, 0)); Matrix3d M3 = new Matrix3d(new Vector3d(1, 4, 7), new Vector3d(2, 5, 8), new Vector3d(3, 6, 9), false); Util.gDevAssert(M.EpsilonEqual(M3, 0)); Util.gDevAssert(M.Transpose().Transpose().EpsilonEqual(M, 0)); Util.gDevAssert(M.EpsilonEqual(new Matrix3d(M.ToBuffer()), 0)); Matrix3d Det = new Matrix3d(6, 1, 1, 4, -2, 5, 2, 8, 7); Util.gDevAssert(Det.Determinant == -306); Matrix3d Mult = M * M; Matrix3d MultResult = new Matrix3d(30, 36, 42, 66, 81, 96, 102, 126, 150); Util.gDevAssert(Mult.EpsilonEqual(MultResult, 0)); Matrix3d Mult2 = new Matrix3d(M * M.Column(0), M * M.Column(1), M * M.Column(2), false); Util.gDevAssert(Mult2.EpsilonEqual(MultResult, 0)); } { Random r = new Random(31337); Vector3d[] axes = TestUtil.RandomPoints3(100, r, Vector3d.Zero); double[] angles = TestUtil.RandomScalars(100, r, new Interval1d(-180, 180)); Vector3d[] testPts = TestUtil.RandomPoints3(100, r, Vector3d.Zero, 10); for (int k = 0; k < angles.Length; ++k) { Vector3d axis = axes[k].Normalized; double angle = angles[k]; Vector3d pt = testPts[k]; Matrix3d MRotAxis = Matrix3d.AxisAngleD(axis, angle); Quaterniond QRotAxis = Quaterniond.AxisAngleD(axis, angle); Util.gDevAssert( (MRotAxis * pt).EpsilonEqual(QRotAxis * pt, 100 * MathUtil.Epsilon)); Matrix3d QRotAxisM = QRotAxis.ToRotationMatrix(); Util.gDevAssert(MRotAxis.EpsilonEqual(QRotAxisM, 10 * MathUtil.Epsilon)); Quaterniond QuatCons = new Quaterniond(MRotAxis); Util.gDevAssert( (QuatCons * pt).EpsilonEqual(QRotAxis * pt, 100 * MathUtil.Epsilon)); // test 3x3 SVD Matrix3d tmpM = MRotAxis; tmpM[0, 0] += 0.0001; tmpM[1, 1] -= 0.0001; tmpM[0, 2] += 0.1; SingularValueDecomposition fullsvd = new SingularValueDecomposition(3, 3, 999); uint result = fullsvd.Solve(tmpM.ToBuffer(), -1); double[] U = new double[9], V = new double[9], S = new double[3]; fullsvd.GetU(U); fullsvd.GetV(V); fullsvd.GetSingularValues(S); Matrix3d MU = new Matrix3d(U), MV = new Matrix3d(V); Matrix3d Sdiag = new Matrix3d(S[0], S[1], S[2]); // U is eigenvectors of ATA, V is eigenvectors of AAT Vector3d rRight = Vector3d.Zero, rLeft = Vector3d.Zero; Matrix3d ATA = tmpM.Transpose() * tmpM, AAT = tmpM * tmpM.Transpose(); for (int j = 0; j < 3; ++j) { double eval = Sdiag[j, j] * Sdiag[j, j]; Vector3d right_evec = MV.Column(j); rRight[j] = (ATA * right_evec - eval * right_evec).Length; Vector3d left_evec = MU.Column(j); rLeft[j] = (AAT * left_evec - eval * left_evec).Length; } Util.gDevAssert(rRight.Length < MathUtil.ZeroTolerancef && rLeft.Length < MathUtil.ZeroTolerancef); // [RMS] if U or V contains a reflection, we need to get rid of it if (MU.Determinant < 0) { MU *= -1; Sdiag *= -1; } if (MV.Determinant < 0) { MV *= -1; Sdiag *= -1; } Matrix3d MRecons = MU * Sdiag * MV.Transpose(); Util.gDevAssert((tmpM * pt).EpsilonEqual(MRecons * pt, 1000 * MathUtil.Epsilon)); Quaterniond qU = new Quaterniond(MU); Util.gDevAssert((MU * pt).EpsilonEqual(qU * pt, 100 * MathUtil.Epsilon)); Quaterniond qV = new Quaterniond(MV.Transpose()); Util.gDevAssert((MV.Transpose() * pt).EpsilonEqual(qV * pt, 100 * MathUtil.Epsilon)); Vector3d ptQ = qU * (Sdiag * (qV * pt)); Util.gDevAssert((tmpM * pt).EpsilonEqual(ptQ, 1000 * MathUtil.Epsilon)); Matrix3d MQRecons = qU.ToRotationMatrix() * Sdiag * qV.ToRotationMatrix(); Util.gDevAssert((tmpM * pt).EpsilonEqual(MQRecons * pt, 1000 * MathUtil.Epsilon)); // U is eigenvectors of ATA, V is eigenvectors of AAT Vector3d qRight = Vector3d.Zero, qLeft = Vector3d.Zero; for (int j = 0; j < 3; ++j) { double eval = Sdiag[j, j] * Sdiag[j, j]; Vector3d right_evec = qV.Conjugate().ToRotationMatrix().Column(j); qRight[j] = (ATA * right_evec - eval * right_evec).Length; Vector3d left_evec = qU.ToRotationMatrix().Column(j); qLeft[j] = (AAT * left_evec - eval * left_evec).Length; } Util.gDevAssert(qRight.Length < MathUtil.ZeroTolerancef && qLeft.Length < MathUtil.ZeroTolerancef); double fast_eps = 0.001; FastQuaternionSVD svd = new FastQuaternionSVD(tmpM, MathUtil.Epsilon, 4); Matrix3d QQRecons = svd.ReconstructMatrix(); Util.gDevAssert((tmpM * pt).EpsilonEqual(QQRecons * pt, fast_eps)); Matrix3d svdS = new Matrix3d(svd.S[0], svd.S[1], svd.S[2]); Matrix3d QQRecons2 = svd.U.ToRotationMatrix() * svdS * svd.V.Conjugate().ToRotationMatrix(); Util.gDevAssert((tmpM * pt).EpsilonEqual(QQRecons2 * pt, fast_eps)); Vector3d ptQSVD = svd.U * (svdS * (svd.V.Conjugate() * pt)); Util.gDevAssert((tmpM * pt).EpsilonEqual(ptQSVD, fast_eps)); // U is eigenvectors of ATA, V is eigenvectors of AAT Vector3d qqRight = Vector3d.Zero, qqLeft = Vector3d.Zero; for (int j = 0; j < 3; ++j) { double eval = svdS[j, j] * svdS[j, j]; Vector3d right_evec = svd.V.ToRotationMatrix().Column(j); qqRight[j] = (ATA * right_evec - eval * right_evec).Length; Vector3d left_evec = svd.U.ToRotationMatrix().Column(j); qqLeft[j] = (AAT * left_evec - eval * left_evec).Length; } Util.gDevAssert(qqRight.Length < fast_eps && qqLeft.Length < fast_eps); } } }