/// <summary> /// Overrides <see cref="CADability.GeoObject.ISurfaceImpl.SameGeometry (BoundingRect, ISurface, BoundingRect, double, out ModOp2D)"/> /// </summary> /// <param name="thisBounds"></param> /// <param name="other"></param> /// <param name="otherBounds"></param> /// <param name="precision"></param> /// <param name="firstToSecond"></param> /// <returns></returns> public override bool SameGeometry(BoundingRect thisBounds, ISurface other, BoundingRect otherBounds, double precision, out ModOp2D firstToSecond) { firstToSecond = ModOp2D.Null; if (other is PlaneSurface) { PlaneSurface second = other as PlaneSurface; GeoPoint p = PointAt(thisBounds.GetCenter()); if (Math.Abs(second.Plane.Distance(p)) > precision) { return(false); } p = second.PointAt(otherBounds.GetCenter()); if (Math.Abs(Plane.Distance(p)) > precision) { return(false); } if (Precision.SameDirection(Normal, second.Normal, false)) { GeoPoint2D[] src = new GeoPoint2D[] { GeoPoint2D.Origin, new GeoPoint2D(1, 0), new GeoPoint2D(0, 1) }; GeoPoint2D[] dst = new GeoPoint2D[3]; for (int i = 0; i < 3; ++i) { dst[i] = second.PositionOf(PointAt(src[i])); } firstToSecond = ModOp2D.Fit(src, dst, true); return(true); } else { return(false); } } return(base.SameGeometry(thisBounds, other, otherBounds, precision, out firstToSecond)); }
/// <summary> /// Overrides <see cref="CADability.Actions.ConstructAction.OnSetAction ()"/> /// </summary> public override void OnSetAction() { base.TitleId = "CopyCircularObjects"; BoundingRect result = originals.GetExtent(Frame.ActiveView.ProjectedModel.Projection, true, false); centerPoint = base.ActiveDrawingPlane.ToGlobal(result.GetCenter()); // rotationPoint = base.ActiveDrawingPlane.ToGlobal(result.GetLowerLeft()); rotationPoint = centerPoint; distX = result.Width; if (copCount == 0) { copCount = 4; copAngle = Math.PI / 2.0; } GeoPointInput rotPoint = new GeoPointInput("CopyCircularObjects.RotationPoint"); rotPoint.SetGeoPointEvent += new CADability.Actions.ConstructAction.GeoPointInput.SetGeoPointDelegate(SetRotPoint); rotPoint.GetGeoPointEvent += new CADability.Actions.ConstructAction.GeoPointInput.GetGeoPointDelegate(GetRotPoint); rotPoint.Optional = true; rotPoint.DefinesHotSpot = true; rotPoint.HotSpotSource = "Hotspots.png:0"; IntInput copiesCount = new IntInput("CopyCircularObjects.CopiesCount", copCount); copiesCount.SetMinMax(0, int.MaxValue, true); copiesCount.SetIntEvent += new CADability.Actions.ConstructAction.IntInput.SetIntDelegate(SetCopiesCount); // copiesCount.CalculateIntEvent +=new CADability.Actions.ConstructAction.IntInput.CalculateIntDelegate(CalcCopiesCount); BooleanInput fullCircle = new BooleanInput("CopyCircularObjects.FullCircle", "CopyCircularObjects.FullCircle.Values"); fullCircle.SetBooleanEvent += new CADability.Actions.ConstructAction.BooleanInput.SetBooleanDelegate(SetFullCircle); fullCircle.GetBooleanEvent += new CADability.Actions.ConstructAction.BooleanInput.GetBooleanDelegate(GetFullCircle); copiesAngle = new AngleInput("CopyCircularObjects.CopiesAngle", copAngle); copiesAngle.ReadOnly = !partOfCircle; copiesAngle.Optional = !partOfCircle; copiesAngle.SetAngleEvent += new CADability.Actions.ConstructAction.AngleInput.SetAngleDelegate(SetCopAngle); copiesAngle.GetAngleEvent += new CADability.Actions.ConstructAction.AngleInput.GetAngleDelegate(GetCopAngle); copiesAngle.CalculateAngleEvent += new CADability.Actions.ConstructAction.AngleInput.CalculateAngleDelegate(CalculateCopAngle); BooleanInput rotObject = new BooleanInput("CopyCircularObjects.ObjectsRotation", "CopyCircularObjects.ObjectsRotation.Values"); rotObject.SetBooleanEvent += new CADability.Actions.ConstructAction.BooleanInput.SetBooleanDelegate(SetObjectsRotation); rotObject.GetBooleanEvent += new CADability.Actions.ConstructAction.BooleanInput.GetBooleanDelegate(GetObjectsRotation); base.SetInput(rotPoint, copiesCount, fullCircle, copiesAngle, rotObject); base.OnSetAction(); showCirc(); }
/// <summary> /// Constructs a line passing through <paramref name="location"/> with the provided <paramref name="direction"/> clipped by the /// rectangle <paramref name="clippedBy"/> /// </summary> /// <param name="location">Point on the (extension of the) line </param> /// <param name="direction">Direction of the line</param> /// <param name="clippedBy">Clipping rectangle</param> public Line2D(GeoPoint2D location, GeoVector2D direction, BoundingRect clippedBy) { direction.Norm(); // ist ja ne Kopie // das geht aber eleganter, oder? GeoPoint2D c = Geometry.DropPL(clippedBy.GetCenter(), location, direction); double l = clippedBy.Width + clippedBy.Height; startPoint = c + l * direction; endPoint = c - l * direction; ClipRect clr = new ClipRect(ref clippedBy); clr.ClipLine(ref startPoint, ref endPoint); }
/// <summary> /// Overrides <see cref="CADability.Actions.ConstructAction.OnSetAction ()"/> /// </summary> public override void OnSetAction() { base.TitleId = "CopyMatrixObjects"; BoundingRect result = originals.GetExtent(Frame.ActiveView.ProjectedModel.Projection, true, false); centerPoint = base.ActiveDrawingPlane.ToGlobal(result.GetCenter()); distX = result.Width; distY = result.Height; // da oben static private, werden diese Variablen gemerkt. Beim ersten Mal vorbesetzen: if ((horRight == 0) & (horLeft == 0) & (verUp == 0) & (verDown == 0)) { horRight = 3; verUp = 2; } // da oben static private, wird diese Variable gemerkt. Beim ersten Mal vorbesetzen: if (dirV.IsNullVector()) { dirV = new GeoVector(1.0, 0.0, 0.0); } IntInput horCountRight = new IntInput("CopyMatrixObjects.HorCountRight", horRight); horCountRight.SetMinMax(0, int.MaxValue, true); horCountRight.SetIntEvent += new CADability.Actions.ConstructAction.IntInput.SetIntDelegate(SetHorCountRight); // horCountRight.CalculateIntEvent +=new CADability.Actions.ConstructAction.IntInput.CalculateIntDelegate(CalcHorCountRight); IntInput verCountUp = new IntInput("CopyMatrixObjects.VerCountUp", verUp); verCountUp.SetMinMax(0, int.MaxValue, true); verCountUp.SetIntEvent += new CADability.Actions.ConstructAction.IntInput.SetIntDelegate(SetVerCountUp); // verCountUp.CalculateIntEvent +=new CADability.Actions.ConstructAction.IntInput.CalculateIntDelegate(CalcVerCountUp); horDist = new LengthInput("CopyMatrixObjects.HorDist", distX); horDist.SetDistanceFromLine(centerPoint, centerPoint + (dirV ^ base.ActiveDrawingPlane.Normal)); horDist.SetLengthEvent += new CADability.Actions.ConstructAction.LengthInput.SetLengthDelegate(SetHorDist); verDist = new LengthInput("CopyMatrixObjects.VerDist", distY); verDist.SetDistanceFromLine(centerPoint, centerPoint + dirV); verDist.SetLengthEvent += new CADability.Actions.ConstructAction.LengthInput.SetLengthDelegate(SetVerDist); GeoVectorInput dir = new GeoVectorInput("CopyMatrixObjects.Direction", dirV); dir.Optional = true; dir.SetVectorFromPoint(centerPoint); dir.SetGeoVectorEvent += new CADability.Actions.ConstructAction.GeoVectorInput.SetGeoVectorDelegate(SetDir); dir.IsAngle = true; IntInput horCountLeft = new IntInput("CopyMatrixObjects.HorCountLeft", horLeft); horCountLeft.SetMinMax(0, int.MaxValue, true); horCountLeft.Optional = true; horCountLeft.SetIntEvent += new CADability.Actions.ConstructAction.IntInput.SetIntDelegate(SetHorCountLeft); // horCountLeft.CalculateIntEvent +=new CADability.Actions.ConstructAction.IntInput.CalculateIntDelegate(CalcHorCountLeft); IntInput verCountDown = new IntInput("CopyMatrixObjects.VerCountDown", verDown); verCountDown.SetMinMax(0, int.MaxValue, true); verCountDown.Optional = true; verCountDown.SetIntEvent += new CADability.Actions.ConstructAction.IntInput.SetIntDelegate(SetVerCountDown); // verCountDown.CalculateIntEvent +=new CADability.Actions.ConstructAction.IntInput.CalculateIntDelegate(CalcVerCountDown); base.SetInput(horCountRight, verCountUp, horDist, verDist, dir, horCountLeft, verCountDown); base.OnSetAction(); showMatrix(); }
public static Ellipse2D FromPoints(IEnumerable <GeoPoint2D> points) { GeoPoint2D[] pnts = null; if (points is GeoPoint2D[] a) { pnts = a; } else if (points is List <GeoPoint2D> l) { pnts = l.ToArray(); } else { List <GeoPoint2D> lp = new List <GeoPoint2D>(); foreach (GeoPoint2D point2D in points) { lp.Add(point2D); } pnts = lp.ToArray(); } Vector <double> observedX = new DenseVector(pnts.Length + 1); // there is no need to set values Vector <double> observedY = new DenseVector(pnts.Length + 1); // this is the data we want to achieve, namely 1.0, points on the unit circle distance to origin for (int i = 0; i < observedY.Count; i++) { observedY[i] = 1; } observedY[pnts.Length] = 0; // the scalar product of minor and major axis LevenbergMarquardtMinimizer lm = new LevenbergMarquardtMinimizer(gradientTolerance: 1e-12, maximumIterations: 20); IObjectiveModel iom = ObjectiveFunction.NonlinearModel( new Func <Vector <double>, Vector <double>, Vector <double> >(delegate(Vector <double> vd, Vector <double> ox) // function { // parameters: the homogeneous matrix that projects the ellipse to the unit circle ModOp2D m = new ModOp2D(vd[0], vd[1], vd[2], vd[3], vd[4], vd[5]); DenseVector res = new DenseVector(pnts.Length + 1); for (int i = 0; i < pnts.Length; i++) { GeoPoint2D pp = m * pnts[i]; res[i] = pp.x * pp.x + pp.y * pp.y; } res[pnts.Length] = m[0, 0] * m[0, 1] + m[1, 0] * m[1, 1]; // the axis should be perpendicular #if DEBUG double err = 0.0; for (int i = 0; i < pnts.Length; i++) { err += (res[i] - 1) * (res[i] - 1); } err += res[pnts.Length] * res[pnts.Length]; #endif return(res); }), new Func <Vector <double>, Vector <double>, Matrix <double> >(delegate(Vector <double> vd, Vector <double> ox) // derivatives { // parameters: the homogeneous matrix that projects the ellipse to the unit circle ModOp2D m = new ModOp2D(vd[0], vd[1], vd[2], vd[3], vd[4], vd[5]); var prime = new DenseMatrix(pnts.Length + 1, 6); for (int i = 0; i < pnts.Length; i++) { GeoPoint2D pp = m * pnts[i]; prime[i, 0] = 2 * pnts[i].x * pp.x; prime[i, 1] = 2 * pnts[i].y * pp.x; prime[i, 2] = 2 * pp.x; prime[i, 3] = 2 * pnts[i].x * pp.y; prime[i, 4] = 2 * pnts[i].y * pp.y; prime[i, 5] = 2 * pp.y; } prime[pnts.Length, 0] = m[0, 1]; prime[pnts.Length, 1] = m[0, 0]; prime[pnts.Length, 2] = 0; prime[pnts.Length, 3] = m[1, 1]; prime[pnts.Length, 4] = m[1, 0]; prime[pnts.Length, 5] = 0; return(prime); }), observedX, observedY); BoundingRect ext = new BoundingRect(pnts); NonlinearMinimizationResult mres = lm.FindMinimum(iom, new DenseVector(new double[] { 2.0 / ext.Width, 0, -ext.GetCenter().x, 0, 2.0 / ext.Height, -ext.GetCenter().y })); if (mres.ReasonForExit == ExitCondition.Converged || mres.ReasonForExit == ExitCondition.RelativeGradient) { Vector <double> vd = mres.MinimizingPoint; ModOp2D m = new ModOp2D(vd[0], vd[1], vd[2], vd[3], vd[4], vd[5]); m = m.GetInverse(); return(new Ellipse2D(m * GeoPoint2D.Origin, m * GeoVector2D.XAxis, m * GeoVector2D.YAxis)); } else { return(null); } }
public override ICurve2D GetProjectedCurve(ICurve curve, double precision) { ICurve2D dbg = base.GetProjectedCurve(curve, precision); if (curve is Ellipse elli) { // a circle on the surface is projected to an ellipse in the uv plane GeoPoint2D[] positions = new GeoPoint2D[5]; for (int i = 0; i < 5; i++) { positions[i] = PositionOf(elli.PointAtParam(i * Math.PI * 2.0 / 6.0)); } Ellipse2D elli2d = Ellipse2D.FromFivePoints(positions, true); double prec = precision; if (prec == 0) { prec = Precision.eps; } if (elli2d == null) { BoundingRect ext = new BoundingRect(positions); GaussNewtonMinimizer.Ellipse2DFit(new ToIArray <GeoPoint2D>(positions), ext.GetCenter(), ext.Size / 2.0, ext.Size / 3.0, 0.0, prec, out elli2d); } else { GaussNewtonMinimizer.Ellipse2DFit(new ToIArray <GeoPoint2D>(positions), elli2d.center, elli2d.majrad, elli2d.minrad, elli2d.majorAxis.Angle, prec, out elli2d); } //GeoPoint2D center = PositionOf(elli.Center); //GeoPoint2D maj = PositionOf(elli.Center + elli.MajorAxis); //GeoPoint2D min = PositionOf(elli.Center + elli.MinorAxis); //Geometry.PrincipalAxis(maj - center, min - center, out GeoVector2D majorAxis, out GeoVector2D minorAxis); //Ellipse2D elli2d = new Ellipse2D(center, maj - center, min - center); if (elli2d == null) { return(base.GetProjectedCurve(curve, precision)); } if (elli.IsArc) { double sp = elli2d.PositionOf(PositionOf(elli.StartPoint)); double ep = elli2d.PositionOf(PositionOf(elli.EndPoint)); EllipseArc2D elliarc2d = elli2d.Trim(sp, ep) as EllipseArc2D; // there must be a more sophisticated way to calculate the orientation and which part to use, but the following works: double pm = elliarc2d.PositionOf(PositionOf(elli.PointAt(0.5))); if (pm < 0 || pm > 1) { elliarc2d = elliarc2d.GetComplement(); } pm = elliarc2d.PositionOf(PositionOf(elli.PointAt(0.1))); if (pm > 0.5) { elliarc2d.Reverse(); } return(elliarc2d); } else { // get the correct orientation double pos = elli2d.PositionOf(PositionOf(elli.PointAt(0.1))); if (pos > 0.5) { elli2d.Reverse(); } return(elli2d); } } return(base.GetProjectedCurve(curve, precision)); }