5月的Plugin of the month:教你如何用F#在AutoCAD中生成神奇的螺环(Spiro)

本文介绍了一个使用 F# 编写的 AutoCAD 插件,该插件可以绘制螺线形图形并允许用户通过交互方式调整参数。文章提供了详细的代码实现,并展示了如何利用 F# 的特性来创建更有趣的应用。

这一个有点实验性的:我们的第一个有趣本月插件 (说它有趣是因为它不是为一个重要的与工作有关的目的而设计的:-)

我已经张贴过代码的 版本,但现在是想分享最新的。Scott 已经介绍了该插件,并宣布了它It’s Alive in the Lab

这是我们写的关于使用F#的第一个插件,这意味着一个额外的DLL需要和插件一起复制。除此之外,代码应该就像在VB.NETC#里编写的。

这里粘贴的是F#代码(其它文件,请从Autodesk Labs下载):

 

// Declare a specific namespace and module name

  

module Spiro.Commands

  

// Import managed assemblies

  

open Autodesk.AutoCAD.ApplicationServices

open Autodesk.AutoCAD.Runtime

open Autodesk.AutoCAD.DatabaseServices

open Autodesk.AutoCAD.EditorInput

open Autodesk.AutoCAD.Geometry

open Autodesk.AutoCAD.GraphicsInterface

open System

open DemandLoading

  

// Our global variables

  

let mutable _jigSegs = 1

let mutable _perfectSegs = 10

let mutable _innerOverOuter = 0.125

let mutable _aOverInner = 0.3333

  

// Return a sampling of points along a spiro's path

  

let pointsOnSpiro cenX cenY inRad outRad a tStart tEnd num =

  [|

    for i in tStart .. tEnd * num do

  

      let t = (float i) / (float num)

      let diff = inRad - outRad

      let ratio = inRad / outRad

      let x =

        diff * Math.Cos(ratio * t) +

          a * Math.Cos((1.0 - ratio) * t)

      let y =

        diff * Math.Sin(ratio * t) -

          a * Math.Sin((1.0 - ratio) * t)

  

      yield new Point2d(cenX + x, cenY + y)

  |]

  

// Different modes of acquisition for our jig

  

type AcquireMode =

  | Inner

  | Outer

  | A

  

type SpiroJig() as this = class

  inherit DrawJig()

  

  // Our member variables

  

  let mutable (_pl : Polyline) = null

  let mutable _cen = Point3d.Origin

  let mutable _norm = new Vector3d(0.0,0.0,1.0)

  let mutable _inner = 0.0

  let mutable _outer = 0.0

  let mutable _a = 0.0

  let mutable _mode = Outer

  

  member x.StartJig(ed : Editor, pt, pl) =

  

    // Set our center and start with the outer radius

  

    _cen <- pt

    _pl <- pl

    _mode <- Outer

    _norm <-

      ed.CurrentUserCoordinateSystem.CoordinateSystem3d.Zaxis

  

    let stat = ed.Drag(this)

    if stat.Status = PromptStatus.OK then

  

      // Next we get the inner radius

  

      _mode <- Inner

      let stat = ed.Drag(this)

      if stat.Status = PromptStatus.OK then

  

        // And finally the pen distance

  

        _mode <- A

        let stat = ed.Drag(this)

  

        if stat.Status = PromptStatus.OK then

          _innerOverOuter <- _inner / _outer

          _aOverInner <- _a / _inner

        stat

      else

        stat

    else

      stat 

  

  // Our Sampler function to acquire the various distances

  

  override x.Sampler prompts =

  

    // We're just acquiring distances

  

    let jo = new JigPromptDistanceOptions()

    jo.UseBasePoint <- true

    jo.Cursor <- CursorType.RubberBand

  

    // Local function to acquire a distance and return

    // the appropriate status

  

    let getDist (prompts : JigPrompts)

      (opts : JigPromptDistanceOptions) oldVal =

  

      let res = prompts.AcquireDistance(opts)

      if res.Status <> PromptStatus.OK then

        (SamplerStatus.Cancel, 0.0)

      else

        if oldVal = res.Value then

          (SamplerStatus.NoChange, 0.0)

        else

          (SamplerStatus.OK, res.Value)

  

    // Then we have slightly different behavior depending

    // on the info we're acquiring

  

    match _mode with

  

    // The outer radius...

  

    | Outer ->

      jo.BasePoint <- _cen

      jo.Message <- "/nRadius of outer circle: "

      let (stat, res) = getDist prompts jo _outer

      if stat = SamplerStatus.OK then

        _outer <- res

      stat

  

    // The inner radius...

  

    | Inner ->

      jo.BasePoint <-

        _cen + new Vector3d(_outer, 0.0, 0.0)

      jo.Message <- "/nRadius of smaller circle: "

      let (stat, res) = getDist prompts jo _inner

      if stat = SamplerStatus.OK then

        _inner <- res

      stat

  

    // The pen distance...

  

    | A ->

      jo.BasePoint <-

        _cen + new Vector3d(_outer - _inner, 0.0, 0.0)

      jo.Message <-

        "/nPen distance from center of smaller circle: "

      let (stat, res) = getDist prompts jo _a

      if stat = SamplerStatus.OK then

        _a <- res

      stat

  

  // Our WorldDraw function to display the Spiro and

  // the related temporary graphics

  

  override x.WorldDraw(draw : WorldDraw) =

  

    // Save our current colour, to reset later

  

    let col = draw.SubEntityTraits.Color

  

    // Make our construction geometry green

  

    draw.SubEntityTraits.Color <- (int16 3)

  

    match _mode with

  

    | Outer ->  // Draw the outer circle

  

      draw.Geometry.Circle(_cen, _outer, _norm)

        |> ignore

  

    | Inner ->  // Draw the outer and inner circles

  

      draw.Geometry.Circle(_cen, _outer, _norm)

        |> ignore

      draw.Geometry.Circle

        (_cen + new Vector3d(_outer - _inner, 0.0, 0.0),

        _inner, _norm)

          |> ignore

  

    | A ->  // Draw the outer and inner circles

  

      draw.Geometry.Circle(_cen, _outer, _norm)

        |> ignore

      draw.Geometry.Circle

        (_cen + new Vector3d(_outer - _inner, 0.0, 0.0),

        _inner, _norm)

          |> ignore

  

    // Check the RegenAbort flag...

    // If it's set then we drop out of the function

  

    if not draw.RegenAbort then

  

      draw.SubEntityTraits.Color <- col

  

      // If getting the outer radius fix the other

      // parameters relative to it (as the inner radius

      // comes later we only need to fix the pen distance

      // against it)

  

      if _mode = Outer then

        _inner <- _outer * _innerOverOuter

        _a <- _inner * _aOverInner

      else if _mode = Inner then

        _a <- _inner *_aOverInner

  

      // Generate the polyline with low accuracy

      // (fewer segments == quicker)

  

      if not draw.RegenAbort then

  

        // Generate our polyline

  

        x.Generate(_jigSegs)

  

        if not draw.RegenAbort then

  

          // And then draw it

  

          draw.Geometry.Polyline(_pl, 0, _pl.NumberOfVertices-1)

            |> ignore

  

    true

  

  // Generate a more accurate polyline

  

  member x.Perfect() =

  

    x.Generate(_perfectSegs)

  

  member x.Generate(num) =

  

    // Generate points based on the accuracy

  

    let pts =

      pointsOnSpiro

        _cen.X _cen.Y _inner _outer _a 0 300 num

  

    // Remove all existing vertices but the first

    // (we need at least one, it seems)

  

    while _pl.NumberOfVertices > 1 do

      _pl.RemoveVertexAt(0)

  

    // Add the new vertices to our polyline

  

    for i in 0 .. pts.Length-1 do

      _pl.AddVertexAt(i, pts.[i], 0.0, 0.0, 0.0)

  

    // Remove the first (original) vertex

  

    if _pl.NumberOfVertices > 1 then

      _pl.RemoveVertexAt(0)

  

end

  

// Our jig-based command

  

["ADNPLUGINS", "SPI", CommandFlags.Modal)>]

let spirojig() =

  

  // Let's get the usual helpful AutoCAD objects

  

  let doc =

    Application.DocumentManager.MdiActiveDocument

  let ed = doc.Editor

  let db = doc.Database

  

  // Prompt the user for the center of the spiro

  

  let cenRes = ed.GetPoint("/nSelect center point: ")

  

  if cenRes.Status = PromptStatus.OK then

  

    let cen = cenRes.Value

  

    // Create the polyline and run the jig

  

    let pl = new Polyline()

    let jig = new SpiroJig()

    let res = jig.StartJig(ed, cen, pl)

  

    if res.Status = PromptStatus.OK then

  

      // Perfect the polyline created, smoothing it up

  

      jig.Perfect()

  

      use tr =

        db.TransactionManager.StartTransaction()

  

      // Get appropriately-typed BlockTable and BTRs

  

      let bt =

        tr.GetObject

          (db.BlockTableId,OpenMode.ForRead)

          :?> BlockTable

  

      let ms =

        tr.GetObject

          (bt.[BlockTableRecord.ModelSpace],

          OpenMode.ForWrite)

          :?> BlockTableRecord

  

      // Add our polyline to the modelspace

  

      let id = ms.AppendEntity(pl)

      tr.AddNewlyCreatedDBObject(pl, true)

  

      tr.Commit()

  

["ADNPLUGINS", "SPISEGS", CommandFlags.Modal)>]

let spiroSegments() =

  

  // Let's get the usual helpful AutoCAD objects

  

  let doc =

    Application.DocumentManager.MdiActiveDocument

  let ed = doc.Editor

  let db = doc.Database

  

  // Prompt the user for the center of the spiro

  

  let pio =

    new PromptIntegerOptions(

      "/nEnter segment resolution for jigged spiro: ")

  pio.LowerLimit <- 1

  pio.UpperLimit <- 20

  pio.DefaultValue <- _jigSegs

  pio.UseDefaultValue <- true

  

  let segRes = ed.GetInteger(pio)

  

  if segRes.Status = PromptStatus.OK then

  

    _jigSegs <- segRes.Value

  

    pio.Message <-

      "/nEnter segment resolution for perfected spiro: "

    pio.DefaultValue <- _perfectSegs

  

    let segRes = ed.GetInteger(pio)

  

    if segRes.Status = PromptStatus.OK then

  

      _perfectSegs <- segRes.Value

  

["ADNPLUGINS", "REMOVESP", CommandFlags.Modal)>]

let removeSpiro() =

  

  try

    RegistryUpdate.UnregisterForDemandLoading()

  

    let doc =

      Application.DocumentManager.MdiActiveDocument

    doc.Editor.WriteMessage

      ("/nThe Spiro plugin will not be loaded" +

      " automatically in future editing sessions.")

  with _ -> () 

 

 

 

当您运行SPI命令你会看到当你拖拽螺环样的图形时出现的临时图形:

  

 

希望你(或你孩子)将一起享受此乐趣! :-)

下载代码方式:https://pan.quark.cn/s/e2157c05e625 在信息技术领域中,数学问题的复杂求解在很大程度上依赖于数值计算,这在科学计算、工程分析以及数据分析等多个方面尤为重要。线性方程组的求解是数值计算中的一个核心且关键的问题,而雅克比迭代法作为一种有效策略,专门用于处理大规模稀疏线性方程组。这个资源提供了一段采用C++语言编写的雅克比迭代法源代码,配合附带的博客文章,能够帮助使用者深入掌握此方法的基本原理和实际应用。 雅克比迭代法,有时也被称作局部迭代方法,主要用于求解形式为 Ax = b 的线性方程组,其中矩阵A需满足对角占优的条件。对角占优的特性是指矩阵中每个对角线元素的绝对值要大于该行其他元素绝对值之和,这一性质确保了算法的收敛性能。该方法的实施基于矩阵A的雅克比矩阵J,其构成方式为 J = D - L - U,其中D、L和U分别代表矩阵A的对角线部分、下三角部分以及上三角部分。 迭代过程的数学表达式为:x(k+1) = J^-1 * b + (I - J^-1*A) * x(k),在此表达式中,x(k)表示第k次迭代的解向量,x(k+1)则是第k+1次迭代的解向量,I是单位矩阵。每次迭代都利用前一次得到的解来计算下一次的解,迭代会持续进行,直到解的精度达到预设标准或迭代次数达到最大限制。 在使用C++进行编程实现时,主要步骤包括: 1. 初始化阶段:设定初始解向量x(0),并明确迭代过程中的参数,例如最大迭代次数和容许的误差界限。 2. 构建雅克比矩阵:依据矩阵A的非对角元素来形成J矩阵。 3. 迭代计算:依照上述迭代公式计算新的解向量,并验证是否满足终止条件(即当前解与前一次解的差值小于设定的误差界限)。 4. 结果输出...
源码下载地址: https://pan.quark.cn/s/24e22475d2c3 采用SSM框架构建的果蔬生鲜超市平台,亦称为果蔬在线交易系统。其用户界面部分涵盖了:账号登录流程、新用户注册功能、购物车内容维护、订单状态监控、收货地点设置、商品检索服务、商品购买操作等。系统后台则由以下核心单元构成:用户账户维护、收货地址簿维护、商品分类维护、商品信息维护、货品出库单维护、订单状态跟踪、销售业绩统计、系统整体配置等。采用SSM框架构建的果蔬生鲜超市平台,亦称为果蔬在线交易系统。其用户界面部分涵盖了:账号登录流程、新用户注册功能、购物车内容维护、订单状态监控、收货地点设置、商品检索服务、商品购买操作等。系统后台则由以下核心单元构成:用户账户维护、收货地址簿维护、商品分类维护、商品信息维护、货品出库单维护、订单状态跟踪、销售业绩统计、系统整体配置等。采用SSM框架构建的果蔬生鲜超市平台,亦称为果蔬在线交易系统。其用户界面部分涵盖了:账号登录流程、新用户注册功能、购物车内容维护、订单状态监控、收货地点设置、商品检索服务、商品购买操作等。系统后台则由以下核心单元构成:用户账户维护、收货地址簿维护、商品分类维护、商品信息维护、货品出库单维护、订单状态跟踪、销售业绩统计、系统整体配置等。采用SSM框架构建的果蔬生鲜超市平台,亦称为果蔬在线交易系统。其用户界面部分涵盖了:账号登录流程、新用户注册功能、购物车内容维护、订单状态监控、收货地点设置、商品检索服务、商品购买操作等。系统后台则由以下核心单元构成:用户账户维护、收货地址簿维护、商品分类维护、商品信息维护、货品出库单维护、订单状态跟踪、销售业绩统计、系统整体配置等。
源码下载地址: https://pan.quark.cn/s/a4b39357ea24 在当前文档中,我们将详细研究如何运用Eclipse集成开发境(IDE)的自定义CSS选项来调整其所有视窗的背景色调以及其他常用视窗的色调。Eclipse作为一个功能强大的开源开发平台,能够支持多种编程语言,包括Java、C++以及Python等。对于那些长时间运用Eclipse的开发专业人士而言,个性化界面色调能够显著提升工作舒适感和效率。让我们深入理解Eclipse的色彩配置机制。Eclipse依托于SWT(Standard Widget Toolkit)框架,允许用户通过调整主题和CSS样式来改变其视觉呈现。在默认设置下,Eclipse会采用系统级别的视窗色调,但用户可以通过覆盖特定的CSS文件来实现个性化定制,而无需触及操作系统本身的设置。 实施步骤1:定位Eclipse的CSS文件 Eclipse的CSS文件通常存储在以下路径位置: ``` <eclipse安装目录>\plugins\org.eclipse.platform_<version>\css ``` 此处,`<eclipse安装目录>`代表用户安装Eclipse的文件夹位置,`<version>`指代Eclipse的版本标识。 实施步骤2:对原始CSS文件进行备份 在进行任何修改之前,务必对原CSS文件进行备份操作,以便在出现问题时能够迅速恢复到原始状态。备份文件通常命名为`e4.css`和`e4_basestyle.css`。 实施步骤3:建立或编辑CSS文件 创建一个新的CSS文件(例如`custom_theme.css`),并插入以下内容以设定窗口背景色: ```css .e4-applicatio...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值