single-yu 发表于 2014-7-26 22:43:01

如何实现动态面积呢

请教大神,如何实现如下图的方法,只看到LISP的程序,但是.NET却没有。烦请大神给个实例,谢谢!



d1742647821 发表于 2023-12-4 20:46:27


效果如下


attach://131119.flv



powered By IFox 需要使用ifox类库才可使用
https://gitee.com/inspirefunction/ifoxcad



namespace DYH.Demo测试;

public static class Test
{
   
    public static void TestArea()
    {
      // 提示用户选择
      var r1 = Env.Editor.GetEntity("\n选择闭合多段线");
      if (r1.Status != PromptStatus.OK)
            return;
      // 开ifox事务
      using var tr = new DBTrans();
      // 如果对象不是点数量大于2的闭合多段线,则程序结束
      if (tr.GetObject(r1.ObjectId, OpenMode.ForWrite) is not Polyline
                {
                  Closed: true, NumberOfVertices: > 2, HasBulges: false
                }
                pl)
            return;
      // 获取中心点
      var midPoint = pl.GetBoundingBoxEx()!.Value.MidCenter;
      // 文字创建
      using var text1 = DBTextEx.CreateDBText(midPoint, (pl.Area / 1e6).ToString("0.00"), 300,
            AttachmentPoint.MiddleCenter);
      text1.ColorIndex = 1;
      var pickedPoint = r1.PickedPoint.Ucs2Wcs();
      var selectedIndex = (int)Math.Floor(pl.GetParameterAtPoint(pl.GetClosestPointTo(pickedPoint, false)));
      // 拿到两个拉伸坐标
      var stretchIndex1 = selectedIndex;
      var stretchIndex2 = (selectedIndex + 1) % pl.NumberOfVertices;
      // 拿到对应线段
      var ls1 = pl.GetLineSegment2dAt((stretchIndex1 - 1 + pl.NumberOfVertices) % pl.NumberOfVertices);
      var ls2 = pl.GetLineSegment2dAt(stretchIndex2);
      var lsJig = pl.GetLineSegment2dAt(stretchIndex1);
      // 拿到构造线
      var line2d1 = new Line2d(ls1.StartPoint, ls1.Direction);
      var line2d2 = new Line2d(ls2.StartPoint, ls2.Direction);
      var line2dJig = new Line2d(lsJig.StartPoint, lsJig.Direction);
      // 拿到两个
      var lastPoint = lsJig.StartPoint;
      var cci2d = new CurveCurveIntersector2d();
      using var j2 = new JigEx((mpw, _) =>
      {
            var mp2d = mpw.Point2d();
            line2dJig.TransformBy(Matrix2d.Displacement(mp2d - lastPoint));
            cci2d.Set(line2dJig, line2d1);
            if (cci2d.NumberOfIntersectionPoints == 1)
            {
                var pt1 = cci2d.GetPointOnCurve2(0).Point;
                cci2d.Set(line2dJig, line2d2);
                if (cci2d.NumberOfIntersectionPoints == 1)
                {
                  var pt2 = cci2d.GetPointOnCurve2(0).Point;
                  pl.SetPointAt(stretchIndex1, pt1);
                  pl.SetPointAt(stretchIndex2, pt2);
                  pl.Draw();
                  text1.TextString = (pl.Area / 1e6).ToString("0.00");
                  var box = pl.GetBoundingBoxEx()!.Value;
                  text1.Move(text1.AlignmentPoint, box.MidCenter);
                  text1.Height = Math.Min(box.Width, box.Height) * 0.1;
                  text1.AdjustAlignment(tr.Database);
                }
            }

            lastPoint = mp2d;
      });
      j2.DatabaseEntityDraw(wd => wd.Geometry.Draw(pl, text1));
      j2.SetOptions("\n选择位置");
      var r2 = Env.Editor.Drag(j2);
      if (r2.Status != PromptStatus.OK)
      {
            tr.Abort();
            return;
      }

      Env.Editor.Redraw(pl);
    }
}

tiancao100 发表于 2023-12-4 10:53:12



分享一个 Overrule的,VB.net源码

'建筑面积
Namespace ZtJZMJ
    Public Class JZMJ_Overule
      Dim NewRule As New JZMJ
      <CommandMethod("ZtJZMJStart")> _
      Public Sub OveruleStart()
            On Error Resume Next
            ACADFunctions.CreateLayer("Zt_全建筑面积标注", 2, "continuous", LineWeight.ByLineWeightDefault, False, False) '不可打印
            ACADFunctions.CreateLayer("Zt_半建筑面积标注", 2, "continuous", LineWeight.ByLineWeightDefault, False, False) '不可打印

            StartOverRule(RXClass.GetClass(GetType(Autodesk.AutoCAD.DatabaseServices.Polyline)), NewRule)
            Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
            acDoc.Editor.WriteMessage(vbCrLf & "图层分别为: Zt_全建筑面积标注 和 Zt_全建筑面积标注")
            acDoc.Editor.Regen()
      End Sub
      <CommandMethod("ZtJZMJEnd")> _
      Public Sub OveruleEnd()
            EndOverRule(RXClass.GetClass(GetType(Autodesk.AutoCAD.DatabaseServices.Polyline)), NewRule)
            Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
            acDoc.Editor.Regen()
      End Sub
      Public Shared Sub StartOverRule(ByVal CADClass As RXClass, ByVal Rule As Overrule)
            Overrule.AddOverrule(CADClass, Rule, False)
            Overrule.Overruling = True
      End Sub
      Public Shared Sub EndOverRule(ByVal CADClass As RXClass, ByVal Rule As Overrule)
            Overrule.Overruling = False
            Overrule.RemoveOverrule(CADClass, Rule)
      End Sub
    End Class
    Public Class JZMJ
      Inherits DrawableOverrule
      Public Overrides Function WorldDraw(ByVal drawable As Autodesk.AutoCAD.GraphicsInterface.Drawable, ByVal wd As Autodesk.AutoCAD.GraphicsInterface.WorldDraw) As Boolean
            Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
            If TypeOf drawable Is Autodesk.AutoCAD.DatabaseServices.Polyline Then
                Dim PL As Autodesk.AutoCAD.DatabaseServices.Polyline = DirectCast(drawable, Autodesk.AutoCAD.DatabaseServices.Polyline)
                'Dim PL As Autodesk.AutoCAD.DatabaseServices.Polyline = TryCast(drawable, Autodesk.AutoCAD.DatabaseServices.Polyline)
                Dim LN As String = PL.Layer
                If LN.Contains("Zt_全建筑面积") = True And PL.Closed = True Then
                  Dim A As Double = PL.Area
                  Dim P As Point3d = GetCentroid(PL)
                  'P = GetPointAR_Radian(P, Math.PI, 2000)
                  'P = GetPointAR_Radian(P, Math.PI / 2, 200)
                  P = GetPointXY(P, -2000, 200)
                  Dim acMText As MText = New MText()
                  acMText.Layer = "0"   '保存图层,否则双击修改后会变为当前图层
                  acMText.ColorIndex = 256
                  acMText.Rotation = 0
                  acMText.Location = P
                  acMText.Width = 4000
                  acMText.TextHeight = 350
                  acMText.Contents = "\pxqc;{\fSimHei;\W0.7;" & "全建筑面积:" & Format(A / 1000 / 1000, "0.00") & "m2}"
                  acMText.WorldDraw(wd)
                  acMText.Dispose()
                  Return MyBase.WorldDraw(drawable, wd)
                ElseIf LN.Contains("Zt_半建筑面积") = True And PL.Closed = True Then
                  Dim A As Double = PL.Area
                  Dim P As Point3d = GetCentroid(PL)
                  'P = GetPointAR_Radian(P, Math.PI, 2000)
                  'P = GetPointAR_Radian(P, Math.PI / 2, 200)
                  P = GetPointXY(P, -2000, 200)
                  Dim acMText As MText = New MText()
                  acMText.Layer = "0"   '保存图层,否则双击修改后会变为当前图层
                  acMText.ColorIndex = 256
                  acMText.Rotation = 0
                  acMText.Location = P
                  acMText.Width = 4000
                  acMText.TextHeight = 350
                  acMText.Contents = "\pxqc;{\fSimHei;\W0.7;" & "半建筑面积:" & Format(A / 2 / 1000 / 1000, "0.00") & "m2}"
                  acMText.WorldDraw(wd)
                  acMText.Dispose()
                  Return MyBase.WorldDraw(drawable, wd)
                Else
                  Return MyBase.WorldDraw(drawable, wd)
                End If
                Return MyBase.WorldDraw(drawable, wd)
            Else
                '不是多段线
                Return MyBase.WorldDraw(drawable, wd)
            End If
      End Function
      Private Function VectorQ(ByVal pl As Autodesk.AutoCAD.DatabaseServices.Polyline, ByVal pt As Point3d) As Vector3d
            Dim vecDir As New Vector3d(1, 0, 0)
            Dim gripPts As Point3dCollection = New Point3dCollection
            Dim IC1 As IntegerCollection = New IntegerCollection
            Dim IC2 As IntegerCollection = New IntegerCollection
            pl.GetGripPoints(gripPts, IC1, IC2)
            'gripPts.ClearCenterPt(1)
            Dim i As Integer = 0
            While i < gripPts.Count - 1
                Dim ln As New LineSegment3d(gripPts(i), gripPts(i + 1))
                Dim ptOnCrv3d As PointOnCurve3d = ln.GetClosestPointTo(pt)
                Dim dDis As Double = ptOnCrv3d.Point.DistanceTo(pt)
                If dDis < 0.0001 Then
                  vecDir = ln.Direction
                  Return vecDir
                End If
                i += 1
            End While
            Return vecDir
      End Function
      Public Function GetPointAR_Radian(ByVal P As Point3d, ByVal Angle As Double, ByVal Radius As Double) As Point3d
            GetPointAR_Radian = New Point3d(P.X + System.Math.Cos(Angle) * Radius, P.Y + System.Math.Sin(Angle) * Radius, P.Z)
      End Function
      Public Function GetPointXY(ByVal P As Point3d, ByVal X As Double, ByVal Y As Double) As Point3d
            GetPointXY = New Point3d(P.X + X, P.Y + Y, P.Z)
      End Function
      '返回两点间中心点
      ''' <summary>
      ''' 返回两点间中心点
      ''' </summary>
      ''' <param name="P1"></param>
      ''' <param name="P2"></param>
      ''' <returns></returns>
      ''' <remarks></remarks>
      Public Function P2P_Center(ByVal P1 As Point3d, ByVal P2 As Point3d) As Point3d
            Return New Point3d((P1.X + P2.X) / 2, _
                            (P1.Y + P2.Y) / 2, _
                            (P1.Z + P2.Z) / 2)
      End Function
      Public Function GetCentroid(ByVal pl As Autodesk.AutoCAD.DatabaseServices.Polyline) As Point3d
            Dim p0 As Point2d = pl.GetPoint2dAt(0)
            Dim cen As New Point2d(0.0, 0.0)
            Dim area As Double = 0.0
            Dim bulge As Double = pl.GetBulgeAt(0)
            Dim last As Integer = pl.NumberOfVertices - 1
            Dim tmpArea As Double
            Dim tmpPoint As Point2d

            If bulge <> 0.0 Then
                Dim datas As Double() = GetArcGeom(pl, bulge, 0, 1)
                area = datas(0)
                cen = New Point2d(datas(1), datas(2)) * datas(0)
            End If
            Dim i As Integer = 1
            While i < last
                tmpArea = TriangleAlgebricArea(p0, pl.GetPoint2dAt(i), pl.GetPoint2dAt(i + 1))
                tmpPoint = TriangleCentroid(p0, pl.GetPoint2dAt(i), pl.GetPoint2dAt(i + 1))
                cen += (tmpPoint * tmpArea).GetAsVector()
                area += tmpArea
                bulge = pl.GetBulgeAt(i)
                If bulge <> 0.0 Then
                  Dim datas As Double() = GetArcGeom(pl, bulge, i, i + 1)
                  area += datas(0)
                  cen += New Vector2d(datas(1), datas(2)) * datas(0)
                End If
                System.Math.Max(System.Threading.Interlocked.Increment(i), i - 1)
            End While
            bulge = pl.GetBulgeAt(last)
            If bulge <> 0.0 Then
                Dim datas As Double() = GetArcGeom(pl, bulge, last, 0)
                area += datas(0)
                cen += New Vector2d(datas(1), datas(2)) * datas(0)
            End If
            cen = cen.DivideBy(area)
            Dim result As New Point3d(cen.X, cen.Y, pl.Elevation)
            Return result.TransformBy(Matrix3d.PlaneToWorld(pl.Normal))
      End Function
      Public Function GetArcGeom(ByVal pl As Autodesk.AutoCAD.DatabaseServices.Polyline, ByVal bulge As Double, ByVal index1 As Integer, ByVal index2 As Integer) As Double()
            Dim arc As CircularArc2d = pl.GetArcSegment2dAt(index1)
            Dim arcRadius As Double = arc.Radius
            Dim arcCenter As Point2d = arc.Center
            Dim arcAngle As Double = 4.0 * Math.Atan(bulge)
            Dim tmpArea As Double = ArcAlgebricArea(arcRadius, arcAngle)
            Dim tmpPoint As Point2d = ArcCentroid(pl.GetPoint2dAt(index1), pl.GetPoint2dAt(index2), arcCenter, tmpArea)
            Dim D As Double() = Nothing
            D.SetValue(tmpArea, 0)
            D.SetValue(tmpPoint.X, 1)
            D.SetValue(tmpPoint.Y, 2)
            Return D
      End Function
      Public Function TriangleCentroid(ByVal p0 As Point2d, ByVal p1 As Point2d, ByVal p2 As Point2d) As Point2d
            Return (p0 + p1.GetAsVector() + p2.GetAsVector()) / 3.0
      End Function
      Public Function TriangleAlgebricArea(ByVal p0 As Point2d, ByVal p1 As Point2d, ByVal p2 As Point2d) As Double
            Return (((p1.X - p0.X) * (p2.Y - p0.Y)) - ((p2.X - p0.X) * (p1.Y - p0.Y))) / 2.0
      End Function
      Public Function ArcCentroid(ByVal start As Point2d, ByVal As Point2d, ByVal cen As Point2d, ByVal tmpArea As Double) As Point2d
            Dim chord As Double = start.GetDistanceTo()
            Dim angle As Double = AngleFromTo(start, )
            Return Polar2d(cen, angle - (Math.PI / 2.0), (chord * chord * chord) / (12.0 * tmpArea))
      End Function
      Public Function ArcAlgebricArea(ByVal rad As Double, ByVal ang As Double) As Double
            Return rad * rad * (ang - Math.Sin(ang)) / 2.0
      End Function
      Public Function AngleFromTo(ByVal p1 As Point2d, ByVal p2 As Point2d) As Double
            Return (p2 - p1).Angle
      End Function
      Public Function Polar2d(ByVal org As Point2d, ByVal angle As Double, ByVal distance As Double) As Point2d
            Return New Point2d(org.X + distance, org.Y).RotateBy(angle, org)
      End Function
    End Class
End Namespace


single-yu 发表于 2014-7-27 19:51:51

飞狐版主,能否指点一下

雪山飞狐_lzh 发表于 2014-7-27 20:00:46

用 Jig 吧最近出差 代码没法写,,,

newbuser 发表于 2014-7-27 20:14:27

别卖关子了,赶紧来段源码怎么样?

single-yu 发表于 2014-7-28 00:27:58

雪山飞狐_lzh 发表于 2014-7-27 20:00 static/image/common/back.gif
用 Jig 吧最近出差 代码没法写,,,

那等老大回来吧,我先研究一下,唉,还是学的不精呀!

mycad 发表于 2014-7-29 17:33:17

等待老大回来写代码,学习!!

liuxu042 发表于 2014-7-31 09:16:18

规则重定义也可实现,求求379539186

single-yu 发表于 2014-7-31 19:34:02

liuxu042 发表于 2014-7-31 09:16 static/image/common/back.gif
规则重定义也可实现,求求379539186

能否给段代码,学习一下,谢谢

雪山飞狐_lzh 发表于 2014-8-4 20:26:51

本帖最后由 雪山飞狐_lzh 于 2014-8-4 20:41 编辑

简单的写了下 只实现了选点的 很多东东都没考虑 O(∩_∩)O~
class PolygonJig: DrawJig
      {

            enum SelectState
            {
                OnPoint,
                OnEdge
            }

            Polyline _pl;
            SelectState state = SelectState.OnPoint;
            Point3d _position;
            int _id;

            public PolygonJig(Polyline pl, int id)
            {
                _pl = pl;
                _id = id;
            }

            protected override SamplerStatus Sampler(JigPrompts prompts)
            {
                switch (state)
                {
                  case SelectState.OnPoint:
                        JigPromptPointOptions jigOpts = new JigPromptPointOptions();
                        jigOpts.UserInputControls =
                            UserInputControls.Accept3dCoordinates |
                            UserInputControls.NoZeroResponseAccepted |
                            UserInputControls.NoNegativeResponseAccepted;
                        PromptPointResult res = prompts.AcquirePoint(jigOpts);

                        Point3d pnt = res.Value;
                        if (pnt != _position)
                            _position = pnt;
                        else
                            return SamplerStatus.NoChange;

                        if (res.Status == PromptStatus.Cancel)
                            return SamplerStatus.Cancel;
                        else
                            return SamplerStatus.OK;

                  case SelectState.OnEdge:
                        return SamplerStatus.Cancel;

                }

                return SamplerStatus.Cancel;

            }

            protected override bool WorldDraw(Autodesk.AutoCAD.GraphicsInterface.WorldDraw draw)
            {
                _pl.SetPointAt(_id, _position.Convert2d(new Plane()));
                draw.Geometry.Draw(_pl);
                draw.Geometry.Text(_position, Vector3d.ZAxis, Vector3d.XAxis, 20, 0.75, 0, _pl.Area.ToString());
                return true;
            }
      }


      
      public static void CC()
      {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;

            var optEnt = new PromptEntityOptions("\n请选择多边形");
            optEnt.SetRejectMessage("选择错误!");
            optEnt.AddAllowedClass(typeof(Polyline), false);
            var resEnt = ed.GetEntity(optEnt);

            if (resEnt.Status != PromptStatus.OK)
                return;

            using (var tr = db.TransactionManager.StartTransaction())
            {

                Polyline pl = tr.GetObject(resEnt.ObjectId, OpenMode.ForWrite) as Polyline;
                pl.Highlight();
               

                int n = Convert.ToInt32(Math.Round(pl.GetParameterAtPoint(pl.GetClosestPointTo(resEnt.PickedPoint, true)), MidpointRounding.AwayFromZero));
                if (n >= pl.EndParam) n = 0;

                var jig = new PolygonJig(pl, n);
                ed.Drag(jig);
                tr.Commit();

            }



                        
      }

hncjddd 发表于 2020-3-21 22:02:01

你好,我想看看这个动态面积的lisp代码可以吗?版主
页: [1] 2
查看完整版本: 如何实现动态面积呢