public void Init(System.Drawing.Point SourcePoint, Projection projection, SnapModes SnapMode, int MaxDist) #endif { this.BestDist = double.MaxValue; this.BestObject = null; this.SnapPointIndex = 0; SourceBeam = projection.PointBeam(SourcePoint); this.SourcePoint = projection.ProjectionPlane.Intersect(SourceBeam); this.Projection = projection; this.SnapPoint = projection.DrawingPlanePoint(SourcePoint); // MaxDist die die maximale Entfernung des Fangpunktes vom aktuellen Punkt bezogen auf die ProjectionPlane #if WEBASSEMBLY GeoPoint2D p1 = projection.ProjectionPlane.Intersect(projection.PointBeam(new CADability.WebDrawing.Point(SourcePoint.X, SourcePoint.Y + MaxDist))); GeoPoint2D p2 = projection.ProjectionPlane.Intersect(projection.PointBeam(new CADability.WebDrawing.Point(SourcePoint.X + MaxDist, SourcePoint.Y))); GeoPoint2D p3 = projection.ProjectionPlane.Intersect(projection.PointBeam(new CADability.WebDrawing.Point(SourcePoint.X, SourcePoint.Y - MaxDist))); GeoPoint2D p4 = projection.ProjectionPlane.Intersect(projection.PointBeam(new CADability.WebDrawing.Point(SourcePoint.X - MaxDist, SourcePoint.Y))); #else GeoPoint2D p1 = projection.ProjectionPlane.Intersect(projection.PointBeam(new System.Drawing.Point(SourcePoint.X, SourcePoint.Y + MaxDist))); GeoPoint2D p2 = projection.ProjectionPlane.Intersect(projection.PointBeam(new System.Drawing.Point(SourcePoint.X + MaxDist, SourcePoint.Y))); GeoPoint2D p3 = projection.ProjectionPlane.Intersect(projection.PointBeam(new System.Drawing.Point(SourcePoint.X, SourcePoint.Y - MaxDist))); GeoPoint2D p4 = projection.ProjectionPlane.Intersect(projection.PointBeam(new System.Drawing.Point(SourcePoint.X - MaxDist, SourcePoint.Y))); #endif this.MaxDist = Math.Max(Math.Max(p1 | this.SourcePoint, p2 | this.SourcePoint), Math.Max(p3 | this.SourcePoint, p4 | this.SourcePoint)); pickArea = projection.GetPickSpace(new Rectangle(SourcePoint.X - MaxDist, SourcePoint.Y - MaxDist, 2 * MaxDist, 2 * MaxDist)); this.BasePointValid = false; this.SnapMode = SnapMode; this.DidSnap = DidSnapModes.DidNotSnap; faceDist = double.MaxValue; }
/// <summary> /// Overrides <see cref="CADability.GeoObject.IGeoObjectImpl.HitTest (Projection.PickArea, bool)"/> /// </summary> /// <param name="area"></param> /// <param name="onlyInside"></param> /// <returns></returns> public override bool HitTest(Projection.PickArea area, bool onlyInside) { // lock (this) { if (onlyInside) { // alle müssen ganz drin sein for (int i = 0; i < containedObjects.Count; ++i) { if (!containedObjects[i].HitTest(area, onlyInside)) { return(false); } } return(true); } else { // wenigsten eines muss teilweise drin sein for (int i = 0; i < containedObjects.Count; ++i) { if (containedObjects[i].HitTest(area, onlyInside)) { return(true); } } return(false); } } }
/// <summary> /// While the normal <see cref="HitTest(Projection.PickArea, bool)">HitTest</see> only checkes the <see cref="Location"/> of the object /// this method checks the hittest of the object expanded according to the projection in this <paramref name="area"/> /// </summary> /// <param name="area">Pick area to check</param> /// <param name="onlyInside">true, if the whole object must reside inside the pickarea, false if overlapping will suffice</param> /// <returns>true when a hit is recognized</returns> public bool RealHitTest(Projection.PickArea area, bool onlyInside) { ModOp m = ModOp.Translate(location.x, location.y, location.z) * ModOp.Scale(area.Projection.DeviceToWorldFactor); IGeoObject clone = geoObject.Clone(); clone.Modify(m); return(clone.HitTest(area, onlyInside)); }
/// <summary> /// Overrides <see cref="CADability.GeoObject.IGeoObjectImpl.HitTest (Projection.PickArea, bool)"/> /// </summary> /// <param name="area"></param> /// <param name="onlyInside"></param> /// <returns></returns> public override bool HitTest(Projection.PickArea area, bool onlyInside) { return(BoundingCube.UnitBoundingCube.Interferes(new GeoPoint[] { area.ToUnitBox *location, area.ToUnitBox *(location + directionWidth), area.ToUnitBox * (location + directionWidth + directionHeight), area.ToUnitBox * (location + directionHeight) }, new int[] { 0, 1, 2, 0, 2, 3 })); }
/// <summary> /// Overrides <see cref="CADability.GeoObject.IGeoObjectImpl.HitTest (Projection.PickArea, bool)"/> /// </summary> /// <param name="area"></param> /// <param name="onlyInside"></param> /// <returns></returns> public override bool HitTest(Projection.PickArea area, bool onlyInside) { GeoPoint sp = area.ToUnitBox * startPoint; GeoPoint ep = area.ToUnitBox * endPoint; if (onlyInside) { return(BoundingCube.UnitBoundingCube.Contains(sp) && BoundingCube.UnitBoundingCube.Contains(ep)); } else { // im Falle !isPerspective ginge es natürlich einfacher, s.o. return(BoundingCube.UnitBoundingCube.Interferes(ref sp, ref ep)); } }
/// <summary> /// Overrides <see cref="CADability.GeoObject.IGeoObjectImpl.HitTest (Projection.PickArea, bool)"/> /// </summary> /// <param name="area"></param> /// <param name="onlyInside"></param> /// <returns></returns> public override bool HitTest(Projection.PickArea area, bool onlyInside) { return(BoundingCube.UnitBoundingCube.Contains(area.ToUnitBox * location)); }
bool IOctTreeInsertable.HitTest(Projection.PickArea area, bool onlyInside) { // kommt nicht dran throw new NotImplementedException(); }
private void ShowContextMenu(Point mousePoint, IView vw) { currentView = vw; GeoObjectList result = new GeoObjectList(); int pickRadius = soa.Frame.GetIntSetting("Select.PickRadius", 5); Projection.PickArea pa = vw.Projection.GetPickSpace(new Rectangle(mousePoint.X - pickRadius, mousePoint.Y - pickRadius, pickRadius * 2, pickRadius * 2)); IActionInputView pm = vw as IActionInputView; GeoObjectList fl = vw.Model.GetObjectsFromRect(pa, new Set <Layer>(pm.GetVisibleLayers()), PickMode.onlyFaces, null); // returns all the face under the cursor // in most cases there is only a single face, which is of interest, only when we have two solids with same or overlapping faces // and one of them is not selectable without also selecting the other, we want both. faces = new List <Face>(); shells = new List <Shell>(); // only Shells, which are not part of a Solid solids = new List <Solid>(); features = new List <IEnumerable <Face> >(); double delta = vw.Model.Extent.Size * 1e-4; double mindist = double.MaxValue; for (int i = 0; i < fl.Count; i++) { if (fl[i] is Face face) // this should always be the case { double z = face.Position(pa.FrontCenter, pa.Direction, 0); if (z < mindist) { if (z < mindist - delta) { faces.Clear(); } faces.Add(face); mindist = z; } } } HashSet <Edge> relevantEdges = new HashSet <Edge>(); for (int i = 0; i < faces.Count; i++) { relevantEdges.UnionWith(faces[i].AllEdges); if (faces[i].Owner is Shell shell) { if (shell.Owner is Solid sld) { if (!solids.Contains(sld)) { solids.Add(sld); } } else { if (!shells.Contains(shell)) { shells.Add(shell); } } } } for (int i = 0; i < faces.Count; i++) { if (faces[i].Owner is Shell shell) { for (int j = 0; j < faces[i].OutlineEdges.Length; j++) { Edge edg = faces[i].OutlineEdges[j]; if (edg.IsPartOfHole(edg.OtherFace(faces[i]))) { Face otherFace = edg.OtherFace(faces[i]); if (otherFace != null) { Edge[] hole = otherFace.GetHole(edg); List <Edge[]> loops = new List <Edge[]> { hole }; List <IEnumerable <Face> > lfeatures = new List <IEnumerable <Face> >(); List <IEnumerable <Face> > lids = new List <IEnumerable <Face> >(); HashSet <Face> startWith = new HashSet <Face>(); foreach (Edge edge in hole) { startWith.Add(edge.OtherFace(otherFace)); // all faces that are connected to the hole in "otherFace" } shell.FeaturesFromEdges(loops, lfeatures, lids, startWith); for (int k = 0; k < lfeatures.Count; k++) { if (lfeatures[k].Count() < shell.Faces.Length * 0.5) { features.Add(lfeatures[k]); } } } } } } } curves = vw.Model.GetObjectsFromRect(pa, new Set <Layer>(pm.GetVisibleLayers()), PickMode.onlyEdges, null); // returns edges and curves edges = new List <Edge>(); // we only accept edges, which belong to one of the selected faces for (int i = curves.Count - 1; i >= 0; --i) { if (curves[i].Owner is Edge edge) { if (relevantEdges.Contains(edge)) { edges.Add(edge); } else { double z = curves[i].Position(pa.FrontCenter, pa.Direction, 0); if (z - delta < mindist) { edges.Add(edge); // this is an edge in front of the closest face } } curves.Remove(i); } else { double z = curves[i].Position(pa.FrontCenter, pa.Direction, 0); if (z - delta > mindist) { curves.Remove(i); } } } // now we have curves, edges, faces, shells and solids (text, hatch, block, dimension not yet implemented) from the right click // we also need access to the already selected edges and faces to GeoObjectList selobj = soa.GetSelectedObjects(); HashSet <Edge> selectedEdges = new HashSet <Edge>(); HashSet <Face> selectedFaces = new HashSet <Face>(); foreach (IGeoObject go in selobj) { if (go is ICurve && go.Owner is Edge edg) { selectedEdges.Add(edg); } if (go is Face fc) { selectedFaces.Add(fc); } } List <MenuWithHandler> cm = new List <MenuWithHandler>(); Shell owningShell = null; if (edges.Count > 0) { owningShell = (edges[0].Owner as Face).Owner as Shell; } if (owningShell == null && faces.Count > 0) { owningShell = (faces[0].Owner as Shell); } if (owningShell == null && selectedFaces.Count > 0) { owningShell = selectedFaces.First().Owner as Shell; } if (owningShell == null && selectedEdges.Count > 0) { owningShell = (selectedEdges.First().Owner as Face).Owner as Shell; } if (owningShell != null) { for (int i = 0; i < features.Count; i++) { List <Face> featureI = new List <Face>(features[i]); MenuWithHandler mh = new MenuWithHandler("MenuId.Feature"); mh.OnSelected = (m, selected) => { currentMenuSelection.Clear(); currentMenuSelection.AddRange(featureI.ToArray()); currentView.Invalidate(PaintBuffer.DrawingAspect.Select, currentView.DisplayRectangle); }; MenuWithHandler positionFeature = new MenuWithHandler("MenuId.Feature.Position"); MenuWithHandler nameFeature = new MenuWithHandler("MenuId.Feature.Name"); mh.SubMenus = new MenuWithHandler[] { positionFeature, nameFeature }; // this is very rudimentary. We have to provide a version of ParametricsDistanceAction, where you can select from and to object. Only axis is implemented Shell shell = featureI[0].Owner as Shell; GeoObjectList fa = shell.FeatureAxis; Line axis = null; foreach (IGeoObject geoObject in fa) { Face axisOf = geoObject.UserData.GetData("CADability.AxisOf") as Face; if (axisOf != null) { if (featureI.Contains(axisOf)) { axis = geoObject as Line; } } if (axis != null) { break; } } positionFeature.OnCommand = (menuId) => { ParametricsDistanceActionOld pd = new ParametricsDistanceActionOld(featureI, soa.Frame); soa.Frame.SetAction(pd); return(true); }; positionFeature.OnSelected = (menuId, selected) => { currentMenuSelection.Clear(); currentMenuSelection.AddRange(featureI.ToArray()); currentView.Invalidate(PaintBuffer.DrawingAspect.Select, currentView.DisplayRectangle); }; nameFeature.OnCommand = (menuId) => { string name = shell.GetNewFeatureName(); shell.AddFeature(name, featureI); if (shell.Owner is Solid sld) { soa.SetSelectedObject(sld); IPropertyEntry toEdit = soa.Frame.ControlCenter.FindItem(name); if (toEdit != null) { List <IPropertyEntry> parents = new List <IPropertyEntry>(); if (toEdit != null) { IPropertyEntry p = toEdit; while ((p = p.Parent as IPropertyEntry) != null) { parents.Add(p); } IPropertyPage propertyPage = parents[parents.Count - 1].Parent as IPropertyPage; if (propertyPage != null) { for (int k = parents.Count - 1; k >= 0; --k) { propertyPage.OpenSubEntries(parents[k], true); } toEdit.StartEdit(false); } } } } return(true); }; nameFeature.OnSelected = (menuId, selected) => { currentMenuSelection.Clear(); currentMenuSelection.AddRange(featureI.ToArray()); currentView.Invalidate(PaintBuffer.DrawingAspect.Select, currentView.DisplayRectangle); }; cm.Add(mh); } } for (int i = 0; i < curves.Count; i++) { // No implementation for simple curves yet. // We would need a logical connection structure as in vertex->edge->face->shell in 2d curves, which we currently do not have. Face faceWithAxis = (curves[i] as IGeoObject).UserData.GetData("CADability.AxisOf") as Face; if (faceWithAxis != null) { MenuWithHandler mh = new MenuWithHandler("MenuId.Axis"); mh.SubMenus = GetFacesSubmenus(faceWithAxis).ToArray(); mh.Target = this; IGeoObject curveI = curves[i] as IGeoObject; mh.OnSelected = (m, selected) => { currentMenuSelection.Clear(); currentMenuSelection.Add(curveI); currentView.Invalidate(PaintBuffer.DrawingAspect.Select, currentView.DisplayRectangle); }; cm.Add(mh); } } for (int i = 0; i < edges.Count; i++) { MenuWithHandler mh = new MenuWithHandler(); mh.ID = "MenuId.Edge." + i.ToString(); mh.Text = StringTable.GetString("MenuId.Edge", StringTable.Category.label); List <MenuWithHandler> lmh = new List <MenuWithHandler>(); MenuWithHandler selectMoreEdges = new MenuWithHandler("MenuId.SelectMoreEdges"); lmh.Add(selectMoreEdges); Edge edgeI = edges[i]; selectMoreEdges.OnCommand = (menuId) => { soa.SetSelectedObject(edgeI.Curve3D as IGeoObject); soa.OverwriteMode(PickMode.onlyEdges); return(true); }; lmh.AddRange(edges[i].GetContextMenu(soa.Frame)); mh.SubMenus = lmh.ToArray(); mh.Target = this; cm.Add(mh); } for (int i = 0; i < faces.Count; i++) { MenuWithHandler mh = new MenuWithHandler(); mh.ID = "MenuId.Face." + i.ToString(); mh.Text = StringTable.GetString("MenuId.Face", StringTable.Category.label); List <MenuWithHandler> lmh = new List <MenuWithHandler>(); MenuWithHandler selectMoreFaces = new MenuWithHandler("MenuId.SelectMoreFaces"); lmh.Add(selectMoreFaces); Face faceI = faces[i]; selectMoreFaces.OnCommand = (menuId) => { soa.SetSelectedObject(faceI); soa.OverwriteMode(PickMode.onlyFaces); return(true); }; lmh.AddRange(GetFacesSubmenus(faces[i])); if (owningShell != null) { double thickness = owningShell.GetGauge(faces[i], out HashSet <Face> frontSide, out HashSet <Face> backSide); if (thickness != double.MaxValue && frontSide.Count > 0) { MenuWithHandler gauge = new MenuWithHandler("MenuId.Gauge"); gauge.OnCommand = (menuId) => { ParametricsOffset po = new ParametricsOffset(frontSide, backSide, soa.Frame, thickness); soa.Frame.SetAction(po); return(true); }; gauge.OnSelected = (menuId, selected) => { currentMenuSelection.Clear(); currentMenuSelection.AddRange(frontSide.ToArray()); currentMenuSelection.AddRange(backSide.ToArray()); currentView.Invalidate(PaintBuffer.DrawingAspect.Select, currentView.DisplayRectangle); }; lmh.Add(gauge); } int n = owningShell.GetFaceDistances(faces[i], out List <Face> distanceTo, out List <double> distance, out List <GeoPoint> pointsFrom, out List <GeoPoint> pointsTo); for (int j = 0; j < n; j++) { if (backSide == null || !backSide.Contains(distanceTo[j])) // this is not already used as gauge { HashSet <Face> capturedFaceI = new HashSet <Face>(new Face[] { faces[i] }); HashSet <Face> capturedDistTo = new HashSet <Face>(new Face[] { distanceTo[j] }); double capturedDistance = distance[j]; GeoPoint capturedPoint1 = pointsFrom[j]; GeoPoint capturedPoint2 = pointsTo[j]; GeoObjectList feedbackArrow = currentView.Projection.MakeArrow(pointsFrom[j], pointsTo[j], currentView.Projection.ProjectionPlane, Projection.ArrowMode.circleArrow); MenuWithHandler faceDist = new MenuWithHandler("MenuId.FaceDistance"); faceDist.OnCommand = (menuId) => { ParametricsDistanceAction pd = new ParametricsDistanceAction(capturedFaceI, capturedDistTo, capturedPoint1, capturedPoint2, soa.Frame); soa.Frame.SetAction(pd); return(true); }; faceDist.OnSelected = (menuId, selected) => { currentMenuSelection.Clear(); currentMenuSelection.AddRange(capturedFaceI.ToArray()); currentMenuSelection.AddRange(capturedDistTo.ToArray()); currentMenuSelection.AddRange(feedbackArrow); currentView.Invalidate(PaintBuffer.DrawingAspect.Select, currentView.DisplayRectangle); }; lmh.Add(faceDist); } } } mh.SubMenus = lmh.ToArray(); mh.Target = this; cm.Add(mh); //cm.AddRange(GetFacesSubmenus(faces)); } for (int i = 0; i < faces.Count; i++) { if (faces[i].Owner is Shell shell) { Shell sh = shell.FeatureFromFace(faces[i]); } } for (int i = 0; i < edges.Count; i++) { if (edges[i].PrimaryFace.Owner is Shell shell) { //shell.FeatureFromEdges(edges[i].PrimaryFace); } } for (int i = 0; i < shells.Count; i++) { MenuWithHandler mh = new MenuWithHandler(); mh.ID = "MenuId.Shell." + i.ToString(); mh.Text = StringTable.GetString("MenuId.Shell", StringTable.Category.label); mh.SubMenus = shells[i].GetContextMenu(soa.Frame); mh.Target = this; cm.Add(mh); } for (int i = 0; i < solids.Count; i++) { MenuWithHandler mh = new MenuWithHandler(); mh.ID = "MenuId.Solid." + i.ToString(); mh.Text = StringTable.GetString("MenuId.Solid", StringTable.Category.label); mh.SubMenus = solids[i].GetContextMenu(soa.Frame); mh.Target = this; cm.Add(mh); } { // selection independent menu items MenuWithHandler mh = new MenuWithHandler(); mh.ID = "MenuId.Show"; mh.Text = StringTable.GetString("MenuId.Show", StringTable.Category.label); MenuWithHandler mhShowHidden = new MenuWithHandler(); mhShowHidden.ID = "MenuId.ShowHidden"; mhShowHidden.Text = StringTable.GetString("MenuId.ShowHidden", StringTable.Category.label); mhShowHidden.OnCommand = (menuId) => { foreach (IGeoObject geoObject in vw.Model) { if (geoObject.Layer != null && geoObject.Layer.Name == "CADability.Hidden") { Layer layer = geoObject.UserData.GetData("CADability.OriginalLayer") as Layer; if (layer != null) { geoObject.Layer = layer; } } } return(true); }; MenuWithHandler mhShowAxis = new MenuWithHandler(); mhShowAxis.ID = "MenuId.ShowAxis"; mhShowAxis.Text = StringTable.GetString("MenuId.ShowAxis", StringTable.Category.label); mhShowAxis.OnCommand = (menuId) => { bool isOn = false; foreach (IGeoObject geoObject in vw.Model) { Shell shell = null; if (geoObject is Solid solid) { shell = solid.Shells[0]; } else if (geoObject is Shell sh) { shell = sh; } if (shell != null && shell.FeatureAxis.Count > 0) { isOn = shell.FeatureAxis[0].IsVisible; break; } } using (vw.Canvas.Frame.Project.Undo.UndoFrame) { foreach (IGeoObject geoObject in vw.Model) { if (geoObject is Solid solid) { solid.ShowFeatureAxis = !isOn; } else if (geoObject is Shell shell) { shell.ShowFeatureAxis = !isOn; } } } return(true); }; mhShowAxis.OnUpdateCommand = (menuId, commandState) => { bool isOn = false; foreach (IGeoObject geoObject in vw.Model) { Shell shell = null; if (geoObject is Solid solid) { shell = solid.Shells[0]; } else if (geoObject is Shell sh) { shell = sh; } if (shell != null && shell.FeatureAxis.Count > 0) { isOn = shell.FeatureAxis[0].IsVisible; break; } } commandState.Checked = isOn; return(true); }; mh.SubMenus = new MenuWithHandler[] { mhShowHidden, mhShowAxis }; mh.Target = this; cm.Add(mh); } vw.SetPaintHandler(PaintBuffer.DrawingAspect.Select, new PaintView(OnRepaintSelect)); mousePoint.X += vw.DisplayRectangle.Width / 8; // find a better place for the menu position, using the extent of the objects vw.Canvas.ShowContextMenu(cm.ToArray(), mousePoint, ContextMenuCollapsed); }
bool IOctTreeInsertable.HitTest(Projection.PickArea area, bool onlyInside) { throw new Exception("The method or operation is not implemented."); }
/// <summary> /// Overrides <see cref="CADability.GeoObject.IGeoObjectImpl.HitTest (Projection.PickArea, bool)"/> /// </summary> /// <param name="area"></param> /// <param name="onlyInside"></param> /// <returns></returns> public override bool HitTest(Projection.PickArea area, bool onlyInside) { return(Flattened.HitTest(area, onlyInside)); }