private void CollectConnectedFillets(Face face, HashSet <Face> connectedFillets) { if (!connectedFillets.Contains(face)) { connectedFillets.Add(face); if (face.Surface is ISurfaceOfArcExtrusion extrusion) { foreach (Edge edge in face.OutlineEdges) { Face otherFace = edge.OtherFace(face); if (otherFace.IsFillet() && otherFace.Surface is ISurfaceOfArcExtrusion otherExtrusion && Precision.IsEqual(extrusion.Radius, otherExtrusion.Radius)) { // if (edge.Curve2D(face).DirectionAt(0.5).IsMoreHorizontal == extrusion.ExtrusionDirectionIsV && otherFace.Surface is ISurfaceOfArcExtrusion arcExtrusion) { CollectConnectedFillets(otherFace, connectedFillets); } } else if (otherFace.Surface is SphericalSurface ss && Precision.IsEqual(ss.RadiusX, extrusion.Radius)) { CollectConnectedFillets(otherFace, connectedFillets); } } }
/// <summary> /// Overrides <see cref="CADability.GeoObject.ISurfaceImpl.GetPlaneIntersection (PlaneSurface, double, double, double, double, double)"/> /// </summary> /// <param name="pl"></param> /// <param name="umin"></param> /// <param name="umax"></param> /// <param name="vmin"></param> /// <param name="vmax"></param> /// <param name="precision"></param> /// <returns></returns> public override IDualSurfaceCurve[] GetPlaneIntersection(PlaneSurface pl, double umin, double umax, double vmin, double vmax, double precision) { if (firstCurve is Line && secondCurve is Line) { if (Precision.IsPerpendicular(firstCurve.StartDirection, pl.Normal, false) && Precision.IsPerpendicular(secondCurve.StartDirection, pl.Normal, false)) { // eine Ebene, die zu beiden Linien parallel ist GeoPoint sp1, ep1, sp2, ep2; sp1 = firstCurve.PointAt(umin); ep1 = secondCurve.PointAt(umin); sp2 = firstCurve.PointAt(umax); ep2 = secondCurve.PointAt(umax); GeoPoint2D[] ip1 = pl.GetLineIntersection(sp1, ep1 - sp1); GeoPoint2D[] ip2 = pl.GetLineIntersection(sp2, ep2 - sp2); if (ip1.Length == 1 && ip2.Length == 1) { GeoPoint sp = pl.PointAt(ip1[0]); GeoPoint ep = pl.PointAt(ip2[0]); double v = Geometry.LinePar(sp1, ep1, sp); Line line = Line.Construct(); line.SetTwoPoints(sp, ep); DualSurfaceCurve dsc = new DualSurfaceCurve(line, this, new Line2D(new GeoPoint2D(umin, v), new GeoPoint2D(umax, v)), pl, new Line2D(ip1[0], ip2[0])); return(new IDualSurfaceCurve[] { dsc }); } } } if (firstCurve is Ellipse && secondCurve is Ellipse) { Ellipse e1 = firstCurve as Ellipse; Ellipse e2 = secondCurve as Ellipse; if (Precision.SameDirection(pl.Normal, e1.Plane.Normal, false) && Precision.SameDirection(pl.Normal, e2.Plane.Normal, false)) { if (e1.IsCircle && e2.IsCircle) { GeoPoint sp1, ep1, sp2, ep2, spm, epm; sp1 = firstCurve.PointAt(umin); ep1 = secondCurve.PointAt(umin); sp2 = firstCurve.PointAt(umax); ep2 = secondCurve.PointAt(umax); spm = firstCurve.PointAt((umin + umax) / 2.0); epm = secondCurve.PointAt((umin + umax) / 2.0); GeoPoint2D[] ip1 = pl.GetLineIntersection(sp1, ep1 - sp1); GeoPoint2D[] ip2 = pl.GetLineIntersection(sp2, ep2 - sp2); GeoPoint2D[] ipm = pl.GetLineIntersection(spm, epm - spm); if (ip1.Length == 1 && ip2.Length == 1 && ipm.Length == 1) { Ellipse e3 = Ellipse.Construct(); e3.SetArc3Points(pl.PointAt(ip1[0]), pl.PointAt(ipm[0]), pl.PointAt(ip2[0]), pl.Plane); double v = Geometry.LinePar(sp1, ep1, pl.PointAt(ip1[0])); DualSurfaceCurve dsc = new DualSurfaceCurve(e3, this, new Line2D(new GeoPoint2D(umin, v), new GeoPoint2D(umax, v)), pl, e3.GetProjectedCurve(pl.Plane)); return(new IDualSurfaceCurve[] { dsc }); } } } } PlanarState ps1 = firstCurve.GetPlanarState(); PlanarState ps2 = secondCurve.GetPlanarState(); if ((ps1 == PlanarState.UnderDetermined || ps1 == PlanarState.Planar) && (ps2 == PlanarState.UnderDetermined || ps2 == PlanarState.Planar)) { if (Precision.IsPerpendicular(firstCurve.StartDirection, pl.Normal, false) && Precision.IsPerpendicular(secondCurve.StartDirection, pl.Normal, false)) { // beide Kurven sind eben und parallel zur Schnittebene, wir haben also ein festes v und somit eine Zwischenkurve GeoPoint ip = pl.Plane.Intersect(firstCurve.StartPoint, secondCurve.StartPoint - firstCurve.StartPoint); double v = Geometry.LinePar(firstCurve.StartPoint, secondCurve.StartPoint, ip); ICurve cv = FixedV(v, umin, umax); DualSurfaceCurve dsc = new DualSurfaceCurve(cv, this, new Line2D(new GeoPoint2D(umin, v), new GeoPoint2D(umax, v)), pl, cv.GetProjectedCurve(pl.Plane)); return(new IDualSurfaceCurve[] { dsc }); } } return(base.GetPlaneIntersection(pl, umin, umax, vmin, vmax, precision)); }
private List <MenuWithHandler> GetFacesSubmenus(Face face) { List <MenuWithHandler> res = new List <MenuWithHandler>(); if (face.IsFillet()) { HashSet <Face> connectedFillets = new HashSet <Face>(); CollectConnectedFillets(face, connectedFillets); FeatureCommandHandler fch = new FeatureCommandHandler(connectedFillets.ToArray(), this, "MenuId.Fillet"); MenuWithHandler fr = new MenuWithHandler("MenuId.Fillet.ChangeRadius"); fr.OnCommand = (menuId) => { ParametricsRadius pr = new ParametricsRadius(connectedFillets.ToArray(), soa.Frame, true); soa.Frame.SetAction(pr); return(true); }; fr.OnSelected = (mh, selected) => { currentMenuSelection.Clear(); currentMenuSelection.AddRange(connectedFillets.ToArray()); currentView.Invalidate(PaintBuffer.DrawingAspect.Select, currentView.DisplayRectangle); }; MenuWithHandler fd = new MenuWithHandler("MenuId.Fillet.Remove"); fd.OnCommand = (menuId) => { Face[] involvedFaces = connectedFillets.ToArray(); Shell orgShell = involvedFaces[0].Owner as Shell; if (orgShell != null) { RemoveFillet rf = new RemoveFillet(involvedFaces[0].Owner as Shell, new HashSet <Face>(involvedFaces)); Shell sh = rf.Result(); if (sh != null) { using (soa.Frame.Project.Undo.UndoFrame) { sh.CopyAttributes(orgShell); IGeoObjectOwner owner = orgShell.Owner; owner.Remove(orgShell); owner.Add(sh); } } } soa.ResetMode(); return(true); }; fd.OnSelected = (mh, selected) => { currentMenuSelection.Clear(); currentMenuSelection.AddRange(connectedFillets.ToArray()); currentView.Invalidate(PaintBuffer.DrawingAspect.Select, currentView.DisplayRectangle); }; fch.SubMenus = new MenuWithHandler[] { fr, fd }; res.Add(fch); } IEnumerable <Face> connected = face.GetSameSurfaceConnected(); // if (connected.Any()) { List <Face> lconnected = new List <Face>(connected); lconnected.Add(face); BoundingCube ext = BoundingCube.EmptyBoundingCube; foreach (Face fc in connected) { ext.MinMax(fc.GetExtent(0.0)); } // maybe a full sphere, cone, cylinder or torus: // except for the sphere: position axis // except for the cone: change radius or diameter // for the cone: smaller and larger diameter // for cone and cylinder: total length if (face.Surface is CylindricalSurface || face.Surface is CylindricalSurfaceNP || face.Surface is ToroidalSurface) { MenuWithHandler mh = new MenuWithHandler("MenuId.FeatureDiameter"); mh.OnCommand = (menuId) => { ParametricsRadius pr = new ParametricsRadius(lconnected.ToArray(), soa.Frame, false); soa.Frame.SetAction(pr); return(true); }; mh.OnSelected = (menuId, selected) => { currentMenuSelection.Clear(); currentMenuSelection.AddRange(lconnected.ToArray()); currentView.Invalidate(PaintBuffer.DrawingAspect.Select, currentView.DisplayRectangle); }; res.Add(mh); } if (face.Surface is CylindricalSurface || face.Surface is CylindricalSurfaceNP || face.Surface is ConicalSurface) { Line axis = null; if (face.Surface is ICylinder cyl) { axis = cyl.Axis.Clip(ext); } if (face.Surface is ConicalSurface cone) { axis = cone.AxisLine(face.Domain.Bottom, face.Domain.Top); } MenuWithHandler mh = new MenuWithHandler("MenuId.AxisPosition"); mh.OnCommand = (menuId) => { ParametricsDistanceActionOld pd = new ParametricsDistanceActionOld(lconnected, axis, soa.Frame); soa.Frame.SetAction(pd); return(true); }; mh.OnSelected = (menuId, selected) => { currentMenuSelection.Clear(); currentMenuSelection.AddRange(lconnected.ToArray()); currentView.Invalidate(PaintBuffer.DrawingAspect.Select, currentView.DisplayRectangle); }; res.Add(mh); } } if (face.Surface is PlaneSurface pls) { // try to find parallel outline edges to modify the distance Edge[] outline = face.OutlineEdges; for (int j = 0; j < outline.Length - 1; j++) { for (int k = j + 1; k < outline.Length; k++) { if (outline[j].Curve3D is Line l1 && outline[k].Curve3D is Line l2) { if (Precision.SameDirection(l1.StartDirection, l2.StartDirection, false)) { // two parallel outline lines, we could parametrize the distance Edge o1 = outline[j]; Edge o2 = outline[k]; // outline[i] is not captured correctly for the anonymous method. I don't know why. With local copies, it works. double lmin = double.MaxValue; double lmax = double.MinValue; double p = Geometry.LinePar(l1.StartPoint, l1.EndPoint, l2.StartPoint); lmin = Math.Min(lmin, p); lmax = Math.Max(lmax, p); p = Geometry.LinePar(l1.StartPoint, l1.EndPoint, l2.EndPoint); lmin = Math.Max(Math.Min(lmin, p), 0); lmax = Math.Min(Math.Max(lmax, p), 1); GeoPoint p1 = Geometry.LinePos(l1.StartPoint, l1.EndPoint, (lmin + lmax) / 2.0); GeoPoint p2 = Geometry.DropPL(p1, l2.StartPoint, l2.EndPoint); if ((p1 | p2) > Precision.eps) { MenuWithHandler mh = new MenuWithHandler("MenuId.EdgeDistance"); Line feedback = Line.TwoPoints(p1, p2); GeoObjectList feedbackArrow = currentView.Projection.MakeArrow(p1, p2, pls.Plane, Projection.ArrowMode.circleArrow); mh.OnCommand = (menuId) => { ParametricsDistanceActionOld pd = new ParametricsDistanceActionOld(o1, o2, feedback, pls.Plane, soa.Frame); soa.Frame.SetAction(pd); return(true); }; mh.OnSelected = (m, selected) => { currentMenuSelection.Clear(); currentMenuSelection.AddRange(feedbackArrow); currentMenuSelection.Add(o1.OtherFace(face)); currentMenuSelection.Add(o2.OtherFace(face)); currentView.Invalidate(PaintBuffer.DrawingAspect.Select, currentView.DisplayRectangle); }; res.Add(mh); } } } } } } if (res.Count > 6) { List <MenuWithHandler> lm = new List <MenuWithHandler>(); for (int i = 4; i < res.Count; i++) { lm.Add(res[i]); } res.RemoveRange(4, lm.Count); MenuWithHandler subMenu = new MenuWithHandler("MenuId.More"); subMenu.SubMenus = lm.ToArray(); res.Add(subMenu); } return(res); }
private void GetDistanceVector(out GeoPoint startPoint, out GeoPoint endPoint) { startPoint = endPoint = GeoPoint.Invalid; if (fromHere is GeoPoint point1 && toHere is GeoPoint point2) { // I think, all other cases should be eliminated startPoint = point1; endPoint = point2; return; } if (fromHere is Vertex vtx) { if (toHere is Vertex vtx2) { startPoint = vtx.Position; endPoint = vtx2.Position; return; } else if (toHere is Edge edge2) { double pos = edge2.Curve3D.PositionOf(vtx.Position); if (pos >= -1e-6 && pos <= 1 + 1e-6) { startPoint = vtx.Position; endPoint = edge2.Curve3D.PointAt(pos); return; } } else if (toHere is Face fc2) { GeoPoint2D[] fps = fc2.Surface.PerpendicularFoot(vtx.Position); if (fps != null && fps.Length > 0) { endPoint = startPoint = vtx.Position; double minDist = double.MaxValue; for (int i = 0; i < fps.Length; i++) { GeoPoint ep = fc2.Surface.PointAt(fps[i]); double d = ep | startPoint; if (d < minDist) { minDist = d; endPoint = ep; } } return; } } } else if (fromHere is Edge edge) { if (toHere is Vertex vtx2) { double pos = edge.Curve3D.PositionOf(vtx2.Position); if (pos >= -1e-6 && pos <= 1 + 1e-6) { endPoint = vtx2.Position; startPoint = edge.Curve3D.PointAt(pos); return; } } else if (toHere is Edge edge2) { if (edge.Curve3D is Line l1 && edge2.Curve3D is Line l2) { if (Precision.SameDirection(l1.StartDirection, l2.StartDirection, false)) { // two parallel lines double spos = Geometry.LinePar(l1.StartPoint, l1.EndPoint, l2.StartPoint); double epos = Geometry.LinePar(l1.StartPoint, l1.EndPoint, l2.EndPoint); if (epos < spos) { Hlp.Swap(ref spos, ref epos); } if (epos < 0) { spos = (epos + 0.0) / 2.0; epos = 0.0; } else if (spos > 1) { epos = (spos + 1.0) / 2.0; spos = 1.0; } else { spos = Math.Max(0.0, spos); epos = Math.Min(epos, 1.0); } startPoint = Geometry.LinePos(l1.StartPoint, l1.EndPoint, (spos + epos) / 2.0); endPoint = Geometry.DropPL(startPoint, l2.StartPoint, l2.EndPoint); return; } else { // two skewed lines Geometry.ConnectLines(l1.StartPoint, l1.StartDirection, l2.StartPoint, l2.StartDirection, out double pos1, out double pos2); startPoint = Geometry.LinePos(l1.StartPoint, l1.EndPoint, pos1); endPoint = Geometry.LinePos(l2.StartPoint, l2.EndPoint, pos2); return; } } // more cases ... } else if (toHere is Face fc2) { // to fill out } } else if (fromHere is Face face) { // to fill out } }