internal double SpaceFunction(Point2d p, AM_Mesh2d pSpaceFunction) { if (pSpaceFunction != null) { double z = 0; if (pSpaceFunction.GetCoordZ(p, ref z)) { return(z); } } Point2d p0 = Vertex(0).Coord; Point2d p1 = Vertex(1).Coord; Point2d p2 = Vertex(2).Coord; double det = AM_Util.TriArea(p0, p1, p2); Debug.Assert(det != 0); double alfa = AM_Util.TriArea(p0, p, p2) / det; double beta = AM_Util.TriArea(p0, p1, p) / det; double f0 = Vertex(0).Space; double f1 = Vertex(1).Space; double f2 = Vertex(2).Space; double f = f0 + alfa * (f1 - f0) + beta * (f2 - f0); return(f); }
internal void ComputeCircumCircle() { Point2d P1 = Vertex(0).Coord, P2 = Vertex(1).Coord, P3 = Vertex(2).Coord; AM_Util.CircumCircle(P1, P2, P3, ref m_CircumCenter, ref m_CircumRadius); }
internal bool InsertVertex(AM_Mesh2d mesh, Point3d pt, int numGenVertex = 0) { while (numGenVertex < m_GenVertexArray.Count) { int v1 = m_GenVertexArray[numGenVertex]; int v2 = m_GenVertexArray[(numGenVertex + 1) % m_GenVertexArray.Count]; if (v2 < v1) { v2 += m_GenVertexArray.Count; } Point2d p = new Point2d(pt); Point2d p1 = new Point2d(m_ArrayCoord[v1]); Point2d p2 = new Point2d(m_ArrayCoord[v2]); Vector2d vec1 = (p2 - p1); Vector2d vec2 = (p - p1); vec1.Unitize(); vec2.Unitize(); if (AM_Util.IsEqual(vec2.Length, 0)) { double t = (p - p1).Length; for (int i = v1 + 1; i <= v2; i++) { Point2d pv = new Point2d(m_ArrayCoord[i % m_ArrayCoord.Count]); if ((pv - p1).Length > t) { AM_Vertex pVertex = null; if (mesh.InsertPoint(p, pt.Z, out pVertex)) { InsertVertex(i, pVertex); return(true); } else { return(false); } } } } numGenVertex++; } return(false); }
internal bool GetCoordZ(Point2d p, ref double Z) { // Localizza uno spigolo vicino AM_Edge edge = Locate(p); if (edge == null) { return(false); } AM_Face face = null; if (AM_Edge.LeftOf(p, edge)) { face = edge.CcwFace(); } else { face = edge.CwFace(); } Z = 0; if (face == null) { return(false); } Point2d p0 = face.Vertex(0).Coord; Point2d p1 = face.Vertex(1).Coord; Point2d p2 = face.Vertex(2).Coord; double det = AM_Util.TriArea(p0, p1, p2); Debug.Assert(det != 00); double alfa = AM_Util.TriArea(p0, p, p2) / det; double beta = AM_Util.TriArea(p0, p1, p) / det; double f0 = face.Vertex(0).Z; double f1 = face.Vertex(1).Z; double f2 = face.Vertex(2).Z; Z = f0 + alfa * (f1 - f0) + beta * (f2 - f0); return(true); }
internal bool CheckWEdge() { for (int i = 0; i < m_ArrayWEdges.Count; i++) { AM_Edge edge = m_ArrayWEdges[i].Edge(); Debug.Assert(edge.Origin() != edge.Destination()); } for (int i = 0; i < m_ArrayFaces.Count; i++) { AM_Face edge = m_ArrayFaces[i]; double area = AM_Util.TriArea(edge[0].OrgCoord(), edge[1].OrgCoord(), edge[2].OrgCoord()); Debug.Assert(area > 0); } return(true); }
bool BuildMeshBoundary(ref BoundingBox maxRect) { maxRect = BoundingBox.Empty; for (int i = 0; i < m_Loops.Count; i++) { var pLoop = m_Loops[i]; AM_Boundary boundary = new AM_Boundary(); m_ArrayMeshBoundary.Add(boundary); boundary.SetLoopIndex(i); boundary.FlagHole = m_Loops[i].IsClosed; for (int j = 0; j < pLoop.NumSegments; j++) { var pVertex = pLoop.GetVertex(j); boundary.AddPoint(pVertex.Location, pVertex.Space, true); maxRect.Union(AM_Util.To3d(pVertex.Location)); var arrayPoints = pLoop.GetGeneratedPoints(j); for (int k = 0; k < arrayPoints.Count; k++) { // Nota: questa riga serve per gestire l'orientamento // TODO: valuatare se necessaria //int n = (pEdge.m_Index & 0x01) ? (arrayPoint.size() - k - 1) : k; int n = k; var meshPt = arrayPoints[k]; boundary.AddPoint(new Point2d(meshPt.X, meshPt.Y), meshPt.Z); maxRect.Union(new Point3d(meshPt.X, meshPt.Y, 0)); } } } return(true); }
internal bool BuildVertexes(bool bForceEven) { int numSegments = NumSegments; for (int i = 0; i < numSegments; i++) { var crv = m_Curves[i]; var pV1 = m_Vertexes[i]; var pV2 = m_Vertexes[(i + 1) % m_Vertexes.Count]; if (!IsClosed && i == numSegments - 1) { pV2 = m_Vertexes[i + 1]; } double space1 = pV1.Space; double space2 = pV2.Space; Point2d org = pV1.Location; Point2d dest = pV2.Location; Point2d start = AM_Util.To2d(crv.PointAtStart); Point2d end = AM_Util.To2d(crv.PointAtEnd); Debug.Assert(org.EpsilonEquals(start, AM_Util.FLT_EPSILON)); Debug.Assert(dest.EpsilonEquals(end, AM_Util.FLT_EPSILON)); m_GenPoint[i] = new List <Point4d>(); if (!BuildPointFromSpace(bForceEven, org, dest, crv, space1, space2, m_GenPoint[i])) { } } return(true); }
internal bool RecoverGenEdge(AM_Mesh2d mesh, int num, List <Point3d> AddArray, bool bStraight = false) { // se viene inserito un punto per aggiustare la conformità // il flag baddFlag diventa true bool baddFlag = false; if (!m_bFlagHole && num >= m_GenVertexArray.Count) { return(true); } int v1 = m_GenVertexArray[num]; int v2 = m_GenVertexArray[(num + 1) % m_GenVertexArray.Count]; if (v2 < v1) { v2 += GetNumVertex(); } AM_Edge pbase; AM_Edge pprev = pbase = Vertex(v1).Edge; for (int i = v1 + 1; i <= v2; i++) { AM_Vertex pV1 = Vertex((i - 1) % (GetNumVertex())); AM_Vertex pV2 = Vertex((i) % (GetNumVertex())); Point2d orgCoord = pV1.Coord; // si controlla che tutti i vertici siano in sequenza while (true) { Point2d baseCoord = pbase.DestCoord(); Point2d prvCoord = new Point2d(m_ArrayCoord[(i - 1) % (GetNumVertex())]); Point2d destCoord = new Point2d(m_ArrayCoord[i % (GetNumVertex())]); if (baseCoord == destCoord) { // il vertice è in sequenza: si continua con il successivo break; } else { pbase = pbase.Next; if (pbase == pprev) { // il ciclo dell'anello si è chiuso senza trovare il vertice // successivo; è necessario inserire un vertice in mezzeria del // lato mancante if (!bStraight) { // 1. Algoritmo di ripristino del bordo con l'aggiunta del punto medio baddFlag = true; // si segnala l'aggiunta di un vertice Point3d p1 = m_ArrayCoord[i - 1]; Point3d p2 = (m_ArrayCoord[i % (GetNumVertex())]); Point3d mid = 0.5 * (p1 + p2); Point3d insPt = new Point3d(mid.X, mid.Y, 0); // si inserisce un vertice nel mezzo del AM_Vertex pvertex; mesh.InsertPoint(new Point2d(insPt), insPt.Z, out pvertex); if (pvertex == null) { Debug.Assert(false); //throw 6; } InsertVertex(i, pvertex); v2++; AddArray.Add(insPt); // si ricomincia il controllo pbase = Vertex(i - 1).Edge; pprev = pbase; } else { // 2. Algoritmo di ripristino del bordo con swap di spigoli AM_Edge pdest = Vertex(i).Edge; Vector2d dir = destCoord - orgCoord; dir.Unitize(); var m = AM_Util.AffineMatrix(orgCoord, dir); while (pV1.FindEdge(pV2) == null) { bool bCoinc = false; AM_Edge pSearch = pbase; // Si controllano situazioni di appartenenza al lato da ripristinare do { double cosang = Vector2d.Multiply(pSearch.GetVersor(), dir); if (AM_Util.IsEqual(cosang, 1, AM_Util.FLT_EPSILON)) { // Lo spigolo appartiene già al lato da ripristinare InsertVertex(i, pSearch.Destination()); v2++; Point2d dc = pSearch.DestCoord(); AddArray.Add(new Point3d(dc.X, dc.Y, 0)); // si ricomincia il controllo pbase = Vertex(i - 1).Edge; pprev = pbase; bCoinc = true; break; } pSearch = pSearch.Next; } while (pSearch != pbase); if (bCoinc) { break; } // Trova il lato di partenza pSearch = pbase; while (!AM_Util.IsInside(pSearch.GetVector(), pSearch.Next.GetVector(), dir)) { pSearch = pSearch.Next; if (pSearch == pprev) { Debug.Assert(false); //mesh.ExportMesh("RecoverSt7.txt"); return(false); } } AM_Edge pStartEdge = pSearch.CcwEdge(); List <AM_Edge> swapArray = new List <AM_Edge>(); while (pStartEdge.Destination() != pV2) { Point2d o = pStartEdge.OrgCoord(); Point2d d = pStartEdge.DestCoord(); swapArray.Add(pStartEdge); pStartEdge = pStartEdge.Prev; Point2d pt = AM_Util.ToLocal(m, pStartEdge.DestCoord()); if (pt.Y < -AM_Util.FLT_EPSILON) { pStartEdge = pStartEdge.CcwEdge(); Debug.Assert(AM_Util.ToLocal(m, pStartEdge.DestCoord()).Y > 0); } } for (int j = 0; j < swapArray.Count; j++) { AM_Edge pSwapEdge = swapArray[j]; // Vengono ruotati gli spigoli all'interno if (AM_Util.CheckSwapEdge(pSwapEdge)) { Debug.Assert(pSearch.CcwFace() != null && pSearch.Next.CwFace() != null); Debug.Assert(pSwapEdge.CcwFace() != null && pSwapEdge.CwFace() != null); AM_Face.SwapEdge(pSwapEdge); } } } } } } } pbase = Vertex(i % (GetNumVertex())).Edge; pprev = pbase; } return(baddFlag); }
// --- Copia --- AM_Boundary CopyBoundary(AM_Mesh2d source, AM_Mesh2d dest, bool bSameGenVertex = true) { AM_Boundary pCopy = new AM_Boundary(); pCopy.m_LoopIndex = m_LoopIndex; if (bSameGenVertex) { // Il numero dei vertici generati è lo stesso; // viene normalmente usato in caso di 'merge' tra due mesh adiacenti pCopy.m_ArrayCoord.Capacity = m_ArrayCoord.Count; for (int i = 0; i < m_ArrayCoord.Count; i++) { pCopy.m_ArrayCoord[i] = m_ArrayCoord[i]; } pCopy.m_GenVertexArray.Capacity = m_GenVertexArray.Count; for (int i = 0; i < m_GenVertexArray.Count; i++) { pCopy.m_GenVertexArray[i] = m_GenVertexArray[i]; } // Trova il primo vertice int destVertex = dest.ArrayVertexes.Count; int nVertex = dest.AddVertex(new Point2d(m_ArrayCoord[0]), m_ArrayCoord[0].Z); Debug.Assert(nVertex < destVertex); // non vengono aggiunti vertici AM_Vertex pVertex = dest.ArrayVertexes[nVertex]; pVertex.Flag |= 0x01; pCopy.m_ArrayVertex.Add(pVertex); for (int i = 1; i < m_ArrayCoord.Count; i++) { Point2d ptDest = new Point2d(m_ArrayCoord[i]); AM_Edge pEdge = pVertex.Edge; AM_Edge pNextEdge = pEdge.Next; while ((ptDest - pNextEdge.DestCoord()).Length > AM_Util.FLT_EPSILON) { if (pNextEdge == pEdge) { Debug.Assert(false); nVertex = dest.AddVertex(ptDest, 0); Debug.Assert(nVertex < destVertex); pNextEdge = dest.ArrayVertexes[nVertex].Edge.Symm(); break; } pNextEdge = pNextEdge.Next; } pVertex = pNextEdge.Destination(); pVertex.Flag |= 0x01; pCopy.m_ArrayVertex.Add(pVertex); } Debug.Assert(pCopy.m_ArrayVertex.Count == m_ArrayVertex.Count); } else { // Il numero dei vertici generati è diverso; // viene normalmente usato in caso di ricostruzione di contorni pCopy.m_GenVertexArray.Capacity = m_GenVertexArray.Count; for (int i = 1; i < m_GenVertexArray.Count; i++) { Point2d p0 = new Point2d(m_ArrayCoord[m_GenVertexArray[i - 1]]); Point2d p1 = new Point2d(m_ArrayCoord[m_GenVertexArray[i]]); AM_Vertex pV0 = dest.RangeSearch.Search(p0.X, p0.Y); AM_Vertex pV1 = dest.RangeSearch.Search(p1.X, p1.Y); Debug.Assert(pV0 != null && pV1 != null); // La direzione è data dal vettore p0-p1 Vector2d vDir = (p1 - p0); vDir.Unitize(); pCopy.m_GenVertexArray[i - 1] = pCopy.m_ArrayCoord.Count; AM_Vertex pV = pV0; while (pV != pV1) { pCopy.m_ArrayCoord.Add(new Point3d(pV.Coord.X, pV.Coord.Y, 0)); pCopy.m_ArrayVertex.Add(pV); // Trova il vertice successivo double minCos = -double.MaxValue; AM_Edge pEdge = pV.Edge; AM_Edge pDirEdge = null; do { double dirCos = pEdge.GetVersor() * vDir; if (dirCos > minCos) { minCos = dirCos; pDirEdge = pEdge; } pEdge = pEdge.Next; } while (pEdge != pV.Edge); Debug.Assert(AM_Util.IsEqual(minCos, 1)); pV = pDirEdge.Destination(); } } } return(pCopy); }
bool BuildPointFromSpace(bool bForceEven, Point2d org, Point2d dest, Curve crv, double space1, double space2, List <Point4d> GenPoint) { GenPoint.Clear(); double len = crv.GetLength(); var domain = crv.Domain; double step = (space1 + space2) / 2; double dStep = space2 - space1; if (dStep > 0) { double h1 = space1; double h2 = space2; Debug.Assert(h1 != 0 && h2 != 0); // la spaziatura non deve essere nulla double r = (len - h1) / (len - h2); double k = Math.Log(h2 / h1) / Math.Log(r); double kk = 0; int numJoint = AM_Util.IntNear(k); if (numJoint != 0) { kk = Math.Log(r * h2 / h1) / Math.Log(r) / (numJoint + 1); } else { return(false); } Debug.Assert(!bForceEven); for (int j = 0; j < numJoint; j++) { double partialLen = h1 * (Math.Pow(r, kk * (j + 1)) - 1) / (r - 1); double percent = partialLen / len; double space = h1 + (h2 - h1) * percent; double t = percent; Debug.Assert(t > 0 && t < 1); double par = (percent * domain.Length); Point2d newCoord = AM_Util.To2d(crv.PointAt(par)); GenPoint.Add(new Point4d(newCoord.X, newCoord.Y, space, t)); } } else { int n = (int)(len / step); if (bForceEven) { n *= 2; if (n == 0) { n = 2; } } if (n != 0) { for (int k = 1; k < n; k++) { double t = (double)(k) / (double)(n); double space = len / n; double par = (t * domain.Length); Point2d newCoord = AM_Util.To2d(crv.PointAt(domain.Min + par)); GenPoint.Add(new Point4d(newCoord.X, newCoord.Y, space, t)); } } else { return(false); } } return(true); }
protected override Result RunCommand(RhinoDoc doc, RunMode mode) { var ptPuffynessOption = new OptionToggle(m_PointPuffyness, "False", "True"); var ptOffsetOption = new OptionDouble(m_PuffynessOffset, 0.5, double.PositiveInfinity); var ptBorderPuffynessOption = new OptionToggle(m_BorderPuffyness, "False", "True"); var borderOffsetOption = new OptionDouble(m_BorderOffset, 0.5, double.PositiveInfinity); var go = new GetOption(); go.SetCommandPrompt("Get meshing properties"); go.AcceptNothing(true); go.AcceptEnterWhenDone(true); int ptPuffyOptionIndex = go.AddOptionToggle("PointPuffyness", ref ptPuffynessOption); int offsetOptionIndex = go.AddOptionDouble("OffsetPtPuffy", ref ptOffsetOption); int borderPuffyOptionIndex = go.AddOptionToggle("BorderPuffyness", ref ptBorderPuffynessOption); int borderOffsetOptionIndex = go.AddOptionDouble("OffsetBorderPuffy", ref borderOffsetOption); go.Get(); var result = go.Result(); while (result != GetResult.Nothing) { if (result == GetResult.Cancel) { return(Result.Cancel); } int optionIdx = go.OptionIndex(); if (optionIdx == ptPuffyOptionIndex) { m_PointPuffyness = ptPuffynessOption.CurrentValue; } else if (optionIdx == offsetOptionIndex) { m_PuffynessOffset = ptOffsetOption.CurrentValue; } else if (optionIdx == borderPuffyOptionIndex) { m_BorderPuffyness = ptBorderPuffynessOption.CurrentValue; } else if (optionIdx == borderOffsetOptionIndex) { m_BorderOffset = borderOffsetOption.CurrentValue; } result = go.Get(); } ObjRef[] rhObjects; var res = RhinoGet.GetMultipleObjects("Select planar curves and Weight points", false, Rhino.DocObjects.ObjectType.Curve | Rhino.DocObjects.ObjectType.Point, out rhObjects); if (res == Result.Success) { // 1. subdive in sets: Closed curves, Opened Curves, weight points; List <Curve> closed_crvs = new List <Curve>(); List <Curve> opened_crvs = new List <Curve>(); List <Point> weight_points = new List <Point>(); bool puffyness = m_PointPuffyness; double offset = m_PuffynessOffset; bool border_puffyness = m_BorderPuffyness; double border_offset = m_BorderOffset; foreach (var ref_obj in rhObjects) { RhinoObject obj = ref_obj.Object(); if (obj.Geometry is Curve) { var crv = obj.Geometry as Curve; if (crv.IsPlanar()) { if (crv.IsClosed) { closed_crvs.Add(crv); } else { opened_crvs.Add(crv); } } } else if (obj.Geometry is Point) { weight_points.Add(obj.Geometry as Point); } } double space = 1; // 2. Insert curves into mesh AM_Region region = null; Curve border_outer_crv = null; Curve offset_outer_crv = null; if (closed_crvs.Count > 0) { region = new AM_Region(); for (int i = 0; i < closed_crvs.Count; i++) { var crv = closed_crvs[i]; region.AddCurve(crv, space, false); AreaMassProperties area = AreaMassProperties.Compute(crv, AM_Util.FLT_EPSILON); if (area.Area > 0 && border_puffyness) { if (border_outer_crv == null) { border_outer_crv = crv; } var offset_Crvs = crv.Offset(Plane.WorldXY, -border_offset, AM_Util.FLT_EPSILON, CurveOffsetCornerStyle.None); foreach (var c in offset_Crvs) { c.Reverse(); doc.Objects.AddCurve(c); offset_outer_crv = c; region.AddCurve(c, space, true); } } } } else { // TODO Debug.Assert(false); return(Result.Failure); } for (int i = 0; i < weight_points.Count; i++) { var pt = weight_points[i]; region.AddWeigthPoint(pt, space / 2); if (puffyness && offset > 0) { var circle = new ArcCurve(new Circle(pt.Location, offset)); var nurbs = circle.ToNurbsCurve(); region.AddCurve(nurbs, space / 2, true); } } for (int i = 0; i < opened_crvs.Count; i++) { var crv = opened_crvs[i]; region.AddCurve(crv, space, false); if (puffyness && offset > 0) { var n = Vector3d.CrossProduct(crv.TangentAtStart, Vector3d.ZAxis); Curve[] offsetCrv = crv.Offset(crv.PointAtStart + offset * n, Vector3d.ZAxis, offset, AM_Util.FLT_EPSILON, CurveOffsetCornerStyle.Round); foreach (var c in offsetCrv) { doc.Objects.AddCurve(c); region.AddCurve(crv, space, false); } Curve[] offsetCrv2 = crv.Offset(crv.PointAtStart - offset * n, Vector3d.ZAxis, offset, AM_Util.FLT_EPSILON, CurveOffsetCornerStyle.Round); foreach (var c in offsetCrv2) { doc.Objects.AddCurve(c); region.AddCurve(crv, space, false); } } } // 3. Mesh della regione if (region != null) { if (region.BuildMesh()) { // Inserisce i punti del contorno foreach (var loop in region.Loops) { for (int i = 0; i < loop.NumSegments; i++) { var points = loop.GetGeneratedPoints(i); //if (points != null) { // foreach (var p in points) { // doc.Objects.AddPoint(new Point3d(p.X, p.Y, 0)); // } //} } } } // Trasforma in Mesh di Rhino var mesh = region.Mesh2D; if (mesh != null) { Mesh rhino_mesh = new Mesh(); double t = 5; for (int i = 0; i < mesh.ArrayVertexes.Count; i++) { mesh.ArrayVertexes[i].Z = t; } // PostProcessa il puffyness if (puffyness) { for (int i = 0; i < region.ArrayInnerVertex.Count; i++) { var iv = region.ArrayInnerVertex[i]; if (iv.MeshVertex != null) { iv.MeshVertex.Z = (4 / 5d) * t; } // Ricerca i punti nell'intorno fino all'offset (molto grezza!) for (int j = 0; j < mesh.ArrayVertexes.Count; j++) { var v = mesh.ArrayVertexes[j]; double d = (iv.MeshVertex.Coord - v.Coord).Length; if (d < offset) { double r = d / offset; AM_Util.EInterpolation interpolation = AM_Util.EInterpolation.Parabolic; v.Z = AM_Util.Interpolation(interpolation, iv.MeshVertex.Z, t, r); } } } } // Individua i punti all'interno della zona di transizione List <int> transitionVts = new List <int>(); if (border_puffyness && border_offset > 0) { // Individua i vertici di partenza e utilizza u flag di lavoro List <AM_Vertex> transitionStartVts = new List <AM_Vertex>(); for (int i = 0; i < mesh.ArrayVertexes.Count; i++) { var v = mesh.ArrayVertexes[i]; bool is_loop_vertex = (v.Flag & 0x1) > 0; v.Flag &= ~0x02; if (is_loop_vertex && BelongToBorder(v)) { transitionStartVts.Add(v); } } // Si usa 0x04 come flag di lavoro for (int i = 0; i < mesh.ArrayWEdges.Count; i++) { var e = mesh.ArrayWEdges[i]; e.Edge().Flag &= ~0x04; e.Edge().Symm().Flag &= ~0x04; } for (int i = 0; i < transitionStartVts.Count; i++) { var v = transitionStartVts[i]; AddTransitionVertexes(v, transitionVts); } if (offset_outer_crv != null) { foreach (var iv in transitionVts) { var v = mesh.ArrayVertexes[iv]; double par; if (offset_outer_crv.ClosestPoint(AM_Util.To3d(v.Coord), out par, 2 * border_offset)) { Point3d cp = offset_outer_crv.PointAt(par); double r = ((cp - AM_Util.To3d(v.Coord)).Length) / border_offset; double z = AM_Util.Interpolation(AM_Util.EInterpolation.Parabolic, 0.8 * t, t, 1 - r); v.Z = z; } } } } // Facce int totVtx = mesh.ArrayVertexes.Count; for (int iSide = 0; iSide < 2; iSide++) { for (int i = 0; i < mesh.ArrayVertexes.Count; i++) { var v = mesh.ArrayVertexes[i]; Point3d pt = v.Coord3d; if (iSide == 1) { pt.Z = 0; } rhino_mesh.Vertices.Add(pt); } for (int i = 0; i < mesh.ArrayFaces.Count; i++) { var f = mesh.ArrayFaces[i]; int numEdges = f.NumEdges; if (numEdges == 3) { int[] vtx = { f.Vertex(0).Index, f.Vertex(1).Index, f.Vertex(2).Index }; if (iSide == 1) { vtx = new int[] { f.Vertex(0).Index + totVtx, f.Vertex(2).Index + totVtx, f.Vertex(1).Index + totVtx }; } rhino_mesh.Faces.AddFace(vtx[0], vtx[1], vtx[2]); } else if (numEdges == 4) { int[] vtx = { f.Vertex(0).Index, f.Vertex(1).Index, f.Vertex(2).Index, f.Vertex(3).Index }; if (iSide == 1) { vtx = new int[] { f.Vertex(0).Index + totVtx, f.Vertex(3).Index + totVtx, f.Vertex(2).Index + totVtx, f.Vertex(1).Index + totVtx }; } rhino_mesh.Faces.AddFace(vtx[0], vtx[1], vtx[2], vtx[3]); } } } for (int iEdge = 0; iEdge < mesh.ArrayWEdges.Count; iEdge++) { var edge = mesh.ArrayWEdges[iEdge].Edge(); if (edge.CcwFace() == null || edge.CwFace() == null) { // E' uno spigolo di bordo int[] vtx = { edge.Destination().Index, edge.Origin().Index, edge.Origin().Index + totVtx, edge.Destination().Index + totVtx, }; rhino_mesh.Faces.AddFace(vtx[0], vtx[1], vtx[2], vtx[3]); } } rhino_mesh.Normals.ComputeNormals(); rhino_mesh.Compact(); if (doc.Objects.AddMesh(rhino_mesh) != Guid.Empty) { doc.Views.Redraw(); return(Rhino.Commands.Result.Success); } } } return(Result.Success); } return(Result.Cancel); }
internal void AddWeigthPoint(Point pt, double space) { var mv = new AM_RegionVertex(AM_Util.To2d(pt.Location), space); m_ArrayInnerVertex.Add(mv); }
internal static bool LeftOf(Point2d x, AM_Edge pedge) { return(AM_Util.CCW(x, pedge.OrgCoord(), pedge.DestCoord())); }
internal bool InsertPoint(Point2d x, double space, out AM_Vertex pvertex) { pvertex = null; AM_Face face = null; // Localizza uno spigolo vicino AM_Edge edge = Locate(x); if (edge == null) { return(false); } // Localizza il triangolo che contiene il punto x // e imposta 'm_pStartingEdge', primo spigolo del triangolo o del quadrilatero // che deve essere riconnesso al punto x if (AM_Edge.LeftOf(x, edge)) { face = (AM_Face)(edge.CcwFace()); m_StartingEdge = edge.CcwEdge(); } else { face = (AM_Face)(edge.CwFace()); m_StartingEdge = edge.Symm().CcwEdge(); } if (face == null) { return(false); } // Verifica dell'eventuale esistenza del punto if (x == edge.OrgCoord()) { pvertex = edge.Origin(); return(false); } if (x == edge.DestCoord()) { pvertex = edge.Destination(); return(false); } Point2d[] v1 = { face.Vertex(0).Coord, face.Vertex(1).Coord, face.Vertex(2).Coord, }; //isOnEdge = OnEdge(x, edge); AM_Edge pOnEdge = OnFaceEdge(x, face); if (pOnEdge != null) { m_StartingEdge = pOnEdge.CcwEdge(); // il punto si trova su un contorno! AM_Face pCwFace = pOnEdge.CwFace(); AM_Face pCcwFace = pOnEdge.CcwFace(); if (pCwFace == null || pCcwFace == null) { return(false); } } // Il punto è all'interno di un triangolo o su uno spigolo if (face.FaceType == AM_Face.EFaceType.FT_ACTIVE) { DeleteActiveFace(face); } DeleteFace(face); if (pOnEdge != null) { // Cancella lo spigolo su cui si appoggia e // conseguentemente anche l'altro spigolo AM_Face pCwFace = pOnEdge.CwFace(); AM_Face pCcwFace = pOnEdge.CcwFace(); if (pCwFace != null && pCwFace.FaceType == AM_Face.EFaceType.FT_ACTIVE) { DeleteActiveFace(pCwFace); } if (pCcwFace != null && pCcwFace.FaceType == AM_Face.EFaceType.FT_ACTIVE) { DeleteActiveFace(pCcwFace); } DeleteEdge(pOnEdge); } // Inserisce il nuovo vertice nell'array globale pvertex = new AM_Vertex(x, 0, space); if (pvertex == null) { Debug.Assert(false); //throw -1; } int m_nVertex = m_ArrayVertexes.Count; pvertex.Index = m_ArrayVertexes.Count; m_ArrayVertexes.Add(pvertex); // Inserisce i nuovi triangoli (facce) edge = m_StartingEdge.CcwEdge(); int numEdge = (pOnEdge != null? 4 : 3); for (int ne = 0; ne < numEdge; ne++) { AM_Face new_face = new AM_Face(); if (new_face == null) { Debug.Assert(false); //throw -1; } AM_Edge actEdge = edge; edge = edge.CcwEdge(); int [] nCoord = { m_nVertex, actEdge.Vertex.Index, actEdge.DestVertex().Index }; AddFace(new_face, nCoord); if (m_bFlagClassific) { new_face.SetTriangleParameter(m_pSpaceFunction); Classific(new_face); } } // Esamina gli spigoli per assicurare che la condizione di // Delaunay sia soddisfatta edge = m_StartingEdge; m_StartingEdge = m_StartingEdge.CcwEdge(); do { //TRACE_EDGE(edge); AM_Edge t = edge.Prev; if (edge.CwFace() != null && AM_Edge.RightOf(t.DestCoord(), edge) && AM_Util.InCircle(edge.OrgCoord(), t.DestCoord(), edge.DestCoord(), x)) { //TRACE0("Faccia swap: "); //TRACE_EDGE(edge); Swap(edge); edge = edge.Prev; } else if (edge.Next == m_StartingEdge) { // Non ci sono più spigoli break; } else { // Recupera un altro spigolo sospetto edge = edge.Next.CwEdge(); } } while (true); return(true); }
internal double SmoothMesh() { double eps = 0; for (int n = 0; n < m_NumSmoothing; n++) //ripeto Num volte lo smoothing { eps = 0; for (int i = 0; i < m_ArrayVertexes.Count; i++) { // ciclo per tutti i punti interni al dominio AM_Vertex vertex = m_ArrayVertexes[i]; // Versione corretta (AC 16-01-03) // Algoritmo di Optimal Smoothing (Borouchaki-George IJNME vol.40) if (vertex.Flag == 0) // E' un punto smoothabile { Point2d p0 = vertex.Coord; Point2d center = Point2d.Unset; int degree = (int)vertex.Degree(true); if (degree < 2) { continue; } AM_Edge start = vertex.Edge; AM_Edge nextEdge = start; Point2d newCoord = Point2d.Unset; double oldQuality = double.MaxValue; // Valuta la qualità dei triangoli prima dello spostamento // e calcola il nuovo centro for (int j = 0; j < degree; j++) { Debug.Assert(nextEdge.CcwFace() != null); Point2d p1 = nextEdge.DestCoord(); Point2d p2 = nextEdge.Next.DestCoord(); // Punto del teorico triangolo equilatero di p1-p2 Vector2d v = p2 - p1; Point2d mp = 0.5 * (p1 + p2); Point2d np = mp + Math.Sqrt(3d) * v.Length * AM_Util.NormalVersor(v); newCoord += np; double inRadius = 0; double circumRadius = 0; AM_Util.CircumCircle(p0, p1, p2, ref center, ref circumRadius); AM_Util.InCircle(p0, p1, p2, ref center, ref inRadius); double sgnArea = AM_Util.TriArea(p0, p1, p2) > 0 ? 1 : -1; double quality = sgnArea * inRadius / circumRadius; oldQuality = Math.Min(oldQuality, quality); nextEdge = nextEdge.Next; } Debug.Assert(nextEdge == start); newCoord.X /= degree; newCoord.Y /= degree; // Controlla l'accettabilità del nuovo centro double newQuality = double.MaxValue; for (int j = 0; j < degree; j++) { Debug.Assert(nextEdge.CcwFace() != null); Point2d p1 = nextEdge.DestCoord(); Point2d p2 = nextEdge.Next.DestCoord(); double inRadius = 0; double circumRadius = 0; AM_Util.CircumCircle(newCoord, p1, p2, ref center, ref circumRadius); AM_Util.InCircle(newCoord, p1, p2, ref center, ref inRadius); double sgnArea = AM_Util.TriArea(newCoord, p1, p2) > 0? 1 : -1; double quality = sgnArea * inRadius / circumRadius; newQuality = Math.Min(quality, newQuality); nextEdge = nextEdge.Next; } Debug.Assert(nextEdge == start); if (newQuality > 0 && newQuality > oldQuality) { // La qualità viene migliorata, il vertice viene spostato eps += (newCoord - p0).Length; vertex.Coord = newCoord; } } } } return(eps); }