原标题:智能设计 | 建模&仿真(3):力学仿真

智能设计| 建模& 仿真(3) :力学仿真

刘肖健

浙江工业大学

1. 案例描述

画出“磁场的形态”,大致如下图所示:

原理描述:

想象页面中有一个磁铁,它对页面空间中的任何一个坐标位置将产生引力或斥力(假设正极产生引力,负极产生斥力)。如果有多个磁铁,它们的磁力效应将叠加在一起。

反过来,页面空间中的任意一点会受到所有磁铁(正极和负极)的磁力作用,这些力会叠加在一起,最后形成一个合力,合力的方向即该点的磁场方向。

仿真系统输入:

由用户在页面中放入若干磁铁Shape ,或磁单极。请自行设计用户的输入形式,以及正极和负极的标识方式。

仿真系统输出:

给出页面中任意一点的磁场方向和磁场强度。请自行设计磁场的给出方式,比如用一个均匀间隔的矩阵,在每个节点上画出磁场的方向。

说明:

1 )这个任务只给提出了需求,没给出具体形式,请自己设计。

2 )动手前请规划好做事的顺序,比如先设计力的表达方式(大小、方向、作用点),再编写两个力的合力计算方法,再编写多个力的合力计算方法;先编写页面中只有一个磁单极的情况,再编写有多个磁铁的情况,等等。

3 )每做一步,测试无误后再往下走;出了错,就退回上一步。宁可做不完,也不要搞出一个运行不通的程序。

4 )适当记录开发过程(包括做错的),不要只展示一个结果。

2. 规划

确定准备实施这个任务后,我计划分三步走:

1 )模拟一个磁单极的力学效应;

2 )模拟多个磁单极的力学效应;

3 )画满页面的磁场。

用户界面:

只有最后一个按钮是最终要做的,前面两个都是中间过程。作为一个学习案例,我把三个按钮单独做了出来。

3.事件设计

先来设定一下目标实现的方式,这里采用最简单的一种:按钮按下后,根据页面中的“磁铁”正负极来绘制页面上每一点处的磁场方向和磁场强度。如下图所示:

我们这样设计程序事件行为的输入和输出:

1 )磁铁由用户给定,当前页面中的任何一个Shape 都可以被当做磁铁处理,其正负极通过Shape 的Name 属性来标识,由用户设定;

2 )磁场方向通过一个短线段的方向来表达;

3 )磁场强度通过线段的粗细来表达。

实际上还可以给线段加箭头,表达该点处的受力方向。这一步不用编程,可以很快地手工完成。

上图中间有个位置线段细到看不见,这里的受力是零,这个位置叫“拉格朗日点”……是个天文学概念,我们不严格的借用一下。

磁铁可以是各种形状,但只有正负极两点的位置决定了磁场的特性,所以这里就把正极或负极简化成一个圆点,它的图形名称(即Name 属性)分别改为“+ ”和“- ”,如下图右边栏对象管理器中的显示——这里有两个正极(红色)和两个负极(蓝色)。

上图放了两个磁铁,可以想象成有两个直棒或U 形磁铁,愿意把磁铁画出来也行,只是它们的名称不能是“+ ”和“- ”,以免干扰计算。

当然我们还可以设计更复杂、更精细的形式,把磁力线画完整(而不是短线段)也是可以的。

4.磁场方向和强度的计算原理

根据中学物理讲到的力学原理,页面上任意一点的磁场方向和强度是这样计算的:

页面中的任意点O 处,受到正极的吸引力OA 和负极的排斥力OB ;其中OA 是向着正极方向的,OB 是背向负极方向的。OA 的大小与OC1 的长度成反比——离磁铁越近受力越大,越远受力越小;同理,OB 的大小与OC2 的长度成反比。因为OC1 比OC2 短(近),所以OA 比OB 大一些。

OA 与OB 的合力是OF ,它的大小和方向用OA 和OB 通过矢量合成(矢量“加”)可以得到。

页面中可以有若干个正极或负极。

用一个双循环在页面中均匀布点,把每一处的磁场方向和强度都表达出来。表达方式是画一条短线段,线段方向及该处磁场强度,但是用线段长度来表达磁场强度不太好看,整个页面充满长长短短的线会显得很乱。所以可以改用线段的粗细来表达强度,线段越粗磁场强度越大。

线的粗细用s1.Outline.Width 变量来设置,比如设为页面宽度的千分之一:

s1.Outline.Width =ActivePage.SizeWidth/1000

5.按钮1:只有一个磁单极的情况

一般磁铁的正负极是成对出现的,但是只有一个正极或负极(即磁单极)的情况似乎也有,这是个神秘的物理学问题。

n徒手画一个磁单极

我们徒手画一个正的磁单极,形状色彩随意,别忘了给它命名为“+ ”:

n任务内容(按钮的功能)

正磁单极(只有一个)放入页面后,用鼠标在页面上点击一下,程序在点击处画一条线表达该处的受力方向。

在按钮的事件程序Magnet_Click 中增加两句代码:

Dim shift As Long

ActiveDocument.GetUserClick x, y, shift, 10, False, cdrCursorPickOvertarget

GetUserClick 函数是获取当前鼠标点击处的坐标位置。执行到这一句时,鼠标会变为准星形状(一个圆圈中间一个十字);在页面左键点击后鼠标,点击处的两个坐标值分别存入变量x 和y 。“10 ”的意思是等待10 秒,如果10 秒内没有点击,则放弃,鼠标变回箭头。点击后,鼠标也会变回箭头。

Shift 是判断点击鼠标时有没有按下shift 键。最后一个变量cdrCursorPickOvertarget 是指定鼠标的形状,这个值是表示准星形状,还有其他若干种形状可选,敲代码时,敲入前面的逗号后可选列表就会出现,有多达十几种鼠标形状:

因为页面中只有一个正的磁单极,所以鼠标点击处的受力方向应该指向磁单极。

我们准备实现的结果是下图这样的:

这是10 次鼠标点击的结果。可以看到,每条线都与磁铁(红圆)的圆心共线,且离磁铁越近,线越长,表示受力越大。

如果鼠标点击处放一个磁针,则线段方向即磁针负极所指的方向。

n原理

画一条线来表示该点的受力方向和受力大小。既然是一条线,要把它画出来需要确定两个因素:

1)线的起点

起点就是鼠标点击处的坐标,这个我们上面已经说了如何获取了。

2)线的终点

这里我们已经知道了线的方向是从鼠标点击处向着磁铁的方向,再给出一个线的长度就可以确定终点的位置了。线的长度用来表示受力大小。距离磁铁越远,受力越小,那我们就把受力(线的长度)定义为距离的倒数好了。

n计算受力线终点

要计算线的终点,这里解释一下math 模块中的点偏移函数:math.shiftPt(p, p0, p1,d) 。这个函数的作用是: 把p点沿着p0-p1方向移动长度d,返回移动后的坐标。

先定义好三个点的位置变量:

Dim pStart, pEnd, pMag '受力线起点、终点、磁铁位置

受力线起点直接用鼠标点击得到的x 和y :

pStart = Array(x, y)

要找到磁铁位置,首先得找到磁铁。现在页面中只有一个磁铁,即名称为“+ ”的shape ,我们遍历当前页面所有物体找到它,并用s1 表达。

For i= 1 To ActivePage.Shapes.Count

If ActivePage.Shapes(i).Name ="+" Then

Set s1 = ActivePage.Shapes(i)

Exit For

End If

Next

上面的代码中:ActivePage.Shapes.Count 是当前页面中图形的数量,一个个检测它们的名字(Name 属性),如果遇到有名为“+ ”的,则将其赋予s1 ,然后用Exit For 跳出循环,后面的不用再找了,找到一个即可。

磁铁的位置pMag 为:

pMag = Array(s1.PositionX,s1.PositionY)

s1.PositionX 和s1.PositionY 是图形s1 的位置。

这里有个小问题:s1 不是一个点,它是一个有面积的图形,它的“位置”是指的哪一处的位置呢?

对此,CorelDraw 用一个内部变量ReferencePoint 来设置确定图形位置的参考点:

列表中:cdrCenter 表示图形中央,cdrBottomLeft 表示图形左下角点……其他选项的含义也都体现在名称里了。

我们要的磁铁位置显然是中心点。 这句写按钮的事件程序Magnet_Click在最前面,变量定义后,确保使用图形位置信息之前它已经被设置好:

ActiveDocument.ReferencePoint= cdrCenter

现在来计算受力大小,也就是线的长度,我们为它定义一个dForce 变量:

Dim dForce As Double '受力大小(线长)

dForce= 1/math.distPP(pStart, pMag)

这里是假设受力大小跟距离成反比。可能实际上并非如此,如果有更精确的力学计算公式,这句替换一下即可。

函数math.distPP 用来计算两点的距离,这里的两点给出的是就是刚计算出来的pStart 和pMag 。在math 模块中可以看到它的定义,十分简单,就是一个勾股定理的应用而已:

现在条件已经齐备,可以计算线的终点pEnd 了:

pEnd = math.shiftPt(pStart,pStart, pMag, dForce)

上面这句的意思是:把起点pStart (鼠标点击处),沿着pStart 与pMag (磁铁)连线方向移动dForce 那么长一段距离,得到终点pEnd 的坐标。

n画受力线

有了起始点和终点,可以用模块draw 里的polyline 函数画线了:

Dim points

points=Array(pStart, pEnd)

Set s1 = draw.polyLine(points)

定义了一个points 数组,它用来表示画线要通过的一系列点的位置,这里只有两个点,用函数Array 把这两个点组成一个数组,然后赋予points ,然后用这个points 数组作为画线函数polyLine 的参数。

执行一下看看结果:

上述每一个线段的生成方式:先点一下对话框上的按钮,再点一下页面中的位置。线段上的箭头是手工设置的。

可以看到这些线段的箭头都指向磁铁,而且距离磁铁越近的线段越长,表明算法是正确的。

6. 按钮2 :有多个磁单极的情况

n任务内容

页面中有多个磁铁时,磁单极不止一个。可以是多个,可以正负极数量不一致,可以都是正极或负极。你可能会觉得奇怪,磁场怎么可能全是正极没有负极?这种情况也是有的,比如天体系统。所有星球都有引力,万有引力(好像还没发现有斥力的星球),它们相当于宇宙中一个个 正的磁单极,离得越近引力越大,离得越远引力越小,跟磁铁原理一样——引力与距离的关系可能比较复杂,不是简单的反比关系,不过只要能用数学公式表达,就能写进程序。

引力场、磁场、电场等,可以看做同一类事物,爱因斯坦晚年就在从事“ 统一场论”的研究,现在统一得如何了还不清楚,不过我们可以先在这个案例里把它们统一了。

来看看有超过一个磁单极的情况。先放两个做示范,一正一负。

接着首先要处理的问题是多个磁单极的表达。上一节定义了一个pMag 来存储一个磁单极的坐标,这里定义一个pMags 数组来存储所有磁单极的坐标,再定义一个sMags 数组来存储代表磁单极的所有图形。

Dim pMags

Dim sMags As Shape

n找出磁单极及其位置坐标

下一步的任务是把页面中所有的磁单极都找出来,图形放在数组sMags 里,它们的中心坐标放在数组pMags 里。上述两个数组都是动态数组,定义它们时还不知道有几个磁单极,要一个个检测完才知道。

下述代码是动态数组应用的经典案例,要牢记。

Dim pMags

Dim sMags As Shape

ReDim pMags(0)'数组长度定义为1,即先假设只有一个磁单极

ReDim sMags(0) As Shape

For i= 1 To ActivePage.Shapes.Count'遍历当前页面的所有图形,一个个检测是不是磁单极

Set s1 = ActivePage.Shapes(i)

If s1.Name = "+" Or s1.Name ="-" Then'检测名称,是如果是磁单极,则……

Set sMags(UBound(sMags)) = s1'把检测到的磁单极保存在数组末尾

ReDim Preserve sMags(UBound(sMags) + 1)As Shape'数组长度增加一个,已有内容保留

pMags(UBound(pMags)) =Array(s1.PositionX, s1.PositionY)'磁单极坐标保存在数组末尾

ReDim Preserve pMags(UBound(pMags) +1)'数组长度增加一个,已有内容保留

End If

Next

If UBound(sMags) > 0 Then'数组长度大于1时才做这种操作

'去除数组最后一位(数组最后增加的一个,没用到要去掉)

ReDim Preserve sMags(UBound(sMags) - 1) AsShape

ReDim Preserve pMags(UBound(pMags) - 1)

End If

上述代码运行完后,两个数组sMags 和pMags 的长度应该是一样的,有一个磁单极就有一个磁单极中心位置坐标。如果数组长度大于1 (即UBound(pMags)>0 ),则数组长度就是磁单极的数量。如果数组长度为1 (即UBound(pMags)=0 ),则可能有两种情况:一是有一个磁单极,二是一个也没有。因为数组长度一开始就定义为1 ,即使一个磁单极也没找到也不会重新把数组长度定义为0 ,没有这种定义方法。

判断数组里有没有磁单极的方法很简单,就是检测对应的中心坐标pMags(0) 是不是一个数组。如果有磁单极,则pMags(0) 里保存的是它的坐标位置数组Array(s1.PositionX,s1.PositionY) ,否则就不会是数组。

下述代码检测有没有磁单极,如果没有,则跳出程序,给出错误报告,然后结束。

If UBound(pMags) = 0 And (Not IsArray(pMags(0))) Then

MsgBox "Magnets not found."

Exit Sub

End If

IsArray(pMags(0)) 函数用来检测pMags(0) 是否数组,是则返回True ,不是则返回False ;Not 把这个结果反了过来,把True 变成False ,把False 变成True 。

如果UBound(pMags)= 0 和(Not IsArray(pMags(0))) 两个条件同时满足(都是True ),则表示:1 )pMags 数组长度为1 ;2 )pMags 数组的唯一成员pMags(0) 不是数组,不是一个坐标位置。这就表示没找到磁单极,那就歇工吧,Exit Sub 表示退出程序,后面的代码都不用执行了。

n画出所有受力线

上一节实现了在鼠标单击处用一条线段来显示该点受力,这节要实现在鼠标单击处用一条线段来显示该点的 所有受力,及其 合力。

每一个磁单极都会在鼠标点击处产生一条受力线。受力线的做法跟上节类似,可以直接搬过来放在一个循环里面。要注意的是,如果磁单极是负极,线的方向相反,是背离磁单极方向的。具体到程序语句中,就是math.shiftPt(p, p0, p1,d) 中的p0 是磁单极位置坐标,p1 是鼠标点击位置坐标,则点的偏移方向p0-p1 是背离磁单极的。

先获取鼠标点击处的位置,跟上节相同:

Dim shift As Long

ActiveDocument.GetUserClick x, y, shift, 10, False, cdrCursorPickOvertarget

Dim pStart, pEnd

pStart= Array(x, y) '受力线起始点位置即鼠标点击位置

然后是画受力线:

Dim dForce As Double '受力大小(线长)

Dim nMags As Integer: nMags = UBound(sMags) + 1'磁单极数量

Dim points'数组:受力线首尾坐标点位置

For i= 0 To nMags – 1'遍历各磁单极

Set s1 = sMags(i)

dForce = 1 / math.distPP(pStart,pMags(i))'计算受力:与磁单极距离的倒数

'计算末尾点pEnd位置

If s1.Name = "+" Then'正极

pEnd = math.shiftPt(pStart, pStart,pMags(i), dForce)'中间两参数指示了受力方向

ElseIf s1.Name = "-" Then'负极

pEnd = math.shiftPt(pStart, pMags(i),pStart, dForce)'中间两参数指示了受力方向

End If

points = Array(pStart, pEnd)'构建画受力线的点坐标数组

Set s1 = draw.polyLine(points)

s1.Outline.EndArrow = ArrowHeads(3)'设置受力线尾端箭头

Next

上述代码中,循环里面的内容是在只有一个磁单极那个按钮里面写过的,直接拷贝过来。

执行结果:

可以看到每个点的两条受力线分别指向红色的正磁单极,以及背离蓝色的负磁单极。受力的大小(线的长短)也是正确的,与距离成反比。

增加一个正磁单极再执行一次:

观察发现,也是对的,三条线的延伸方向分别穿过三个磁单极。

n画出合力线

下面要把上图的几个受力线算出一个合力,并且也用一条线段画出来。

合力的计算方法很简单,就是把几条受力线所代表的矢量加起来(当然是用矢量运算法则来加)就行了。具体算法可以分为三步:算出每条受力线的矢量、算出合力矢量,最后根据合力矢量画出合力线。

1)算出每条受力线的矢量

从初中数学可以知道,矢量的表达方式跟点坐标是一样的,也就是一个Array(x,y) 数组而已。从受力线计算矢量只要用受力线终点坐标pEnd 减去起始点坐标pStart 即可。按矢量计算法则,两个点的x 坐标和y 坐标分别进行减法运算。

在上面那段代码的循环前面增加一句数组定义:

Dim vForce: ReDimvForce(nMags - 1)

在循环里也增加一句计算式,放在循环里面末尾:

vForce(i) = Array(pEnd(0) -pStart(0), pEnd(1) - pStart(1)

pEnd 的x 值是数组的第一个成员pEnd(0) ,y 值是数组的第二个成员pEnd(1) ;pStart 同样。

2)算出合力

计算合力即对各受力矢量进行加法运算。这个更简单,把所有受力矢量的x 和y 值加在一起即可:

Dim vForceX: vForceX = Array(0, 0) '定义合力,并初始化

For i= 0 To nMags - 1

vForceX(0) = vForceX(0) + vForce(i)(0)'x坐标累加

vForceX(1) = vForceX(1) + vForce(i)(1)'y坐标累加

Next

3)根据合力矢量画出合力线

算出来的vForceX 是一个矢量,要画出合力线还要根据它算出合力线的首尾点坐标才行。

起始点坐标已经算出来的,就是鼠标点击处,即pStart 。

末尾点坐标是pStart 与vForceX 的加和,即两个数组的x 和y 值分别相加。

pEnd= Array(pStart(0) + vForceX(0), pStart(1) + vForceX(1))

points= Array(pStart, pEnd)

Set s1 = draw.polyLine(points)

s1.Outline.EndArrow= ArrowHeads(3)'合力线加箭头

s1.Outline.Color= CreateRGBColor(255, 0, 0)'合力线改为红色

s1.Outline.Width= 10 * s1.Outline.Width'合力线加粗

合力画出来这样,红色粗线是合力:

下面是两个磁单极的情况,可以很清晰地看到合力是两个分力构成的平行四边形的对角线。

n合力线的另一种表达形式

如果要画出整个页面空间每一处的磁场方向,合力线最好长度一致,否则看起来非常不好看。那么合力强度怎么表达呢?可以用线的粗细,而线长都改为等长。

在上述语句pEnd 的计算式后面加一句:

pEnd = math.shiftPt(pStart,pStart, pEnd, ActivePage.SizeWidth / 50)

这句用偏移函数shiftPt 重新计算了pEnd 的位置,新的pEnd 在pStart-pEnd 的连线上。shiftPt 里的第三个参数pEnd 是上一步算出的末尾点坐标。pStart 和pEnd 之间的距离改为了固定值ActivePage.SizeWidth / 50 。现在所有合力线都一样长了。

最一句“合力线加粗”改为动态可变的粗细:

s1.Outline.Width = math.VectorLength(vForceX)/50

math.VectorLength 函数是求一个矢量的长度。这里用合力矢量vForceX 的长度的50 分之一作为合力线的粗细。这个值可以根据测试结果修改成最合适的大小。

把画分力线的语句注释掉(前面加英文单引号“'”)变成注释语句。合力线加箭头的语句也注释掉,因为箭头大小是根据线的粗细来的,大大小小的很难看。加箭头最好用同等粗细的线。

7. 按钮3 :画出整个页面的磁场

把页面当磁场,画出每一点处的合力线,就可以观察到整个磁场的形态了。

方法很简单:在刚才的程序外面套一层循环,对每一个点都做同样处理就行了。只是点的位置不再由用户点击确定,而是程序给定的。

我们把画一条合力线的操作定义为函数(Function ),然后不停地调用这个函数,以点位置作为参数,这样它就可以在每个给定点的位置画合力线了。

n创建一个画单条合力线的函数

建立一个空Function :

Function ForceLine(pStart, dLength As Double, aThick As Double) As Shape

End Function

这个函数有五个参数:

1) sMags 为磁单极图形,是一个数组;

2) pMags 为磁单极坐标位置,也是一个数组;

3) pStart 为绘制合力线的点位置坐标,也是数组,即原程序里面由鼠标点击产生的点坐标;

4) dLength 为合力线的长度;

5) aThick 为合力线的粗细参数,合力线的粗细为aThick 乘以合理矢量长度。

把按钮MultiMagnets的事件子程序代码全部复制到Function里,然后做如下修改:

1) 删除sMags 和pMags 定义与生成的语句,因为它们已经由参数提供;

2) 由参数pStart 提供合力线起始点坐标,所以删除pStart 的定义语句Dim pStart 和赋值语句pStart=Array(x,y) ;

3) 删除获取鼠标点击的语句ActiveDocument.GetUserClick ,因为不需要鼠标点击了;

4) 计算pEnd 的语句中的合力线长参数ActivePage.SizeWidth / 50 改为dLength ;

5) 设置线宽的语句中的“/50 ”这个数字改为“* aThick ”;

6) 在最后增加返回值语句:SetForceLine = s1 ;

7) 删除设置图形参考点的语句ActiveDocument.ReferencePoint= cdrCenter ,一个文档设置一次就行了,不用放在Function 里面多次执行。

n画多条合力线

把第二个按钮中的变量定义和pMags 、sMags 的定义和获取语句,全部复制进来,如下:

Dim i As Integer, j As Integer

Dim x As Double, y As Double

Dim s1 As Shape

ActiveDocument.ReferencePoint= cdrCenter

'------获取磁单极

Dim pMags

Dim sMags As Shape

ReDim pMags(0)''数组长度定义为1,即先假设只有一个磁单极

ReDim sMags(0) As Shape

For i= 1 To ActivePage.Shapes.Count'遍历当前页面的所有图形,一个个检测是不是磁单极

Set s1 = ActivePage.Shapes(i)

If s1.Name = "+" Or s1.Name ="-" Then'检测名称,是如果是磁单极,则……

Set sMags(UBound(sMags)) = s1'把检测到的磁单极保存在数组末尾

ReDim Preserve sMags(UBound(sMags) + 1) As Shape'数组长度增加一个,同时保留已有内容

pMags(UBound(pMags)) =Array(s1.PositionX, s1.PositionY)'磁单极坐标保存在数组末尾

ReDim Preserve pMags(UBound(pMags) +1)'数组长度增加一个,同时保留已有内容

End If

Next

If UBound(sMags) > 0 Then'去除数组最后一位(数组最后增加的一个,没用到要去掉)

ReDim Preserve sMags(UBound(sMags) - 1) As Shape

ReDim Preserve pMags(UBound(pMags) - 1)

End If

If UBound(pMags) = 0 And (Not IsArray(pMags(0))) Then

MsgBox "Magnets not found."

Exit Sub

End If

下面的任务是生成一系列的pStart ,然后对每一个pStart 调用刚编好的函数ForceLine 画合力线。

先把pStart 的定义语句加上,放哪都可以:

Dim pStart

要把整个页面填满,需要一个双循环,每行画多少条合力线,一共画多少行,这样一行行画出来。

每行画的合力线数量可以由用户在界面上给出(最下面的输入框)。

把每行线数输入框命名为nLines ,默认值是20 。

计算画合力线的行列数:

Dim nRows As Integer, nCols As Integer

nCols= nLines.Value

nRows= Int(nCols * ActivePage.SizeHeight / ActivePage.SizeWidth)

列数直接来自用户输入。行数根据页面宽高比和列数计算出来,由于算出来不是整数,要用Int 抹掉小数取整。

然后计算行列间隔距离,以便后面的pStart 起点位置计算:

Dim dx As Double, dy As Double'x和y方向的间隔

dx =ActivePage.SizeWidth / nCols

dy =ActivePage.SizeHeight / nRows

用双循环来画一条条的合力线:

Dim dLen As Double'合力线长

dLen= 0.8 * dx

For i= 0 To nRows

For j = 0 To nCols

x = j * dx

y = i * dy

pStart = Array(x, y)

Set s1 = ForceLine(sMags, pMags,pStart, dLen, 1 / 40)

Next

Next

每一个pStart 需要首先计算出来,作为调用ForceLine 函数的参数。

sMags 和pMags 已经有了,可以直接用。

定义合力线长变量dLen ,其值取列间隔dx 的0.8 倍,可以确保不长不短。

合力线粗细的比例因子选1/40 ,这是测试了几次的结果。

绘制结果:

8. 进一步拓展

绘制磁场的基本技术内容就这么Over 了。这个程序还有很大的拓展余地,比如:

1) 把更多的参数放在界面上让用户输入,如合力线长度、合力线粗细系数、要不要箭头等;

2) 合力线可以有更好看的形式,如做成两端圆头,或甚至摆上一个小指南针的图形,让它的转角跟磁场方向一致,这些都很简单,不停的 复制、粘帖、计算转角即可:

3) 可以把磁力线的曲线形态画出来,而不仅是一系列短线;下图是磁力线的一种画法(这个磁场里有14 个磁单极,都是正极):

4) 可以画出星系引力场;前面说过,这是一种只有引力没有斥力的场,也就是只有正磁单极;

5) 可以自己设计“场”的力学规则,用来生成一些奇怪的(但是好看的)复杂曲线;

6) ……

9.总结

1) 跟前一个案例一样,这个案例的关键也不是编程,而是如何在虚拟世界里再现现实世界的规律;

2)程序中设置了一些可以修改和拓展的模块,如引力和距离的关系,这种关系可能比我们想象的要复杂,但只要有公式,我们就能编写出来;

3)在磁场的视觉化表达上,需要表达里的方向和强度两个信息,这里是用了最简单直接的方法,就是用一条短线的方向和粗细两个特征来表达;我们还可以有更好看的可视化方式,比如用色彩,下图是用HSB中的H色彩分量表达磁场方向(用math.alfaPP函数计算矢量角度),用方块边框粗细表达磁场强度,也可以用方块大小甚至圆角大小来表达;

4)还有些参数可以设置,比如磁铁的磁力大小,可以通过Shape的尺寸给出;

5)如果想画出3D空间的磁场,原理一样,可以在Rhino中编写这个仿真程序;

6)“想法很多,一下手就乱 ”,这是新手的常见问题。本文这个程序 尽管并不复杂,直接面向结果时还是会有些头大;这需要把问题一步一步分解开,分解成简单而清晰的功能模块(比如合力计算),定义成一个个函数,按顺序逐步完善——清晰性可以让复杂的事情变得不那么难搞,当你感到你正在做的不是一项智力活动,而是一项体力工作,这说明够清晰了。

这是我教儿子学编程用过的案例之一,中学物理……学习快乐!返回搜狐,查看更多

责任编辑:

coreldraw的线条怎么变成圆头_智能设计 | 建模仿真(3):力学仿真相关推荐

  1. coreldraw的线条怎么变成圆头_别再穿到处撞的小白鞋了,这五款春夏小皮鞋,不管怎么搭配都好看...

    你还在穿小白鞋吗?虽然它很百搭,但是整条大街的人都在穿小白鞋,所以今年夏天就不要再选择烂大街的小白鞋了,最流行的小皮鞋可以美美的穿上脚啦!其实小皮鞋只要合脚,不会有太劳累疲劳的感觉,而且年轻时尚,很容 ...

  2. coreldraw的线条怎么变成圆头_如何PS包装盒平面图改为立体图

    2019-10-09阅读(105) 江城武汉,李白曾在此写下"黄鹤楼中吹玉笛,江城五月落梅花",因此武汉又称江城蓉城.锦城,天府之国成都.成都,别称"蓉城",中 ...

  3. 超简单的_ps抠图_在线抠图工具_智能抠图_速抠图

    超简单的_ps抠图_在线抠图工具_智能抠图_速抠图 在线ps抠图_速抠图_智能抠图_sukoutu.com 关键词 在线抠图.ps抠图.智能抠图.一键抠图.钢笔抠图.图片处理.证件照换背景.一寸照制作 ...

  4. 工艺路线和工序有差别吗_智能制造、数字化车间、数字化企业需要结构化工艺吗?...

    DGT:未来企业做智能制造,数字化车间及数字化工厂都离不开结构化工艺,结构化工艺是智能制造,数字化车间及数字化工厂的数据核心. 在工业4.0时代,一大批新的理念.技术不断涌现,智能制造.数字化工厂.云 ...

  5. ug冲模标准件库_昆山兴模lt;携手gt;武汉益模,打通冲模“智能设计+精益管理”的最后一道关卡...

    武汉益模科技股份有限公司是国内领先的工业互联网及智能制造的解决方案提供商,为模具.装备.军工.汽车.家电及等有柔性化生产需求的工厂提供专业的智能设计/信息化管理/智能加工/数字化工厂等工业软件.工业机 ...

  6. 【毕业设计】52-基于单片机的车厢智能烟雾报警器设计与仿真(原理图_仿真_配套设计文档_PPT_流程图_外文翻译)

    [毕业设计]52-基于单片机的车厢智能烟雾报警器设计与仿真(原理图/仿真/配套设计文档/PPT/流程图/外文翻译) 文章目录 [毕业设计]52-基于单片机的车厢智能烟雾报警器设计与仿真(原理图/仿真/ ...

  7. C语言单相智能电表课程设计,单相单用户电能表的计_课程设计.doc

    单相单用户电能表的计_课程设计 摘要 此课程设计主要是通过编程来实现电子式数码管显示单相单用户的用电量,其硬件部分主要以C8051F360单片机为控制核心,连接电能计量.LED显示.掉电存储.按键清零 ...

  8. 【四】多智能体强化学习(MARL)近年研究概览 {Learning cooperation(协作学习)、Agents modeling agents(智能体建模)}

    相关文章: [一]最新多智能体强化学习方法[总结] [二]最新多智能体强化学习文章如何查阅{顶会:AAAI. ICML } [三]多智能体强化学习(MARL)近年研究概览 {Analysis of e ...

  9. python 创意编程 全国-关于举办第五届全国青少年创意编程与智能设计大赛的通知...

    各省.自治区.直辖市和新疆生产建设兵团科协青少年科技教育工作机构,青少年科技辅导员协会(科技教育协会): 为深入贯彻落实国务院<新一代人工智能发展规划>的任务要求,向广大青少年普及推广编程 ...

最新文章

  1. SqlServer英文单词全字匹配
  2. ffmpeg avcodec_encode_video2 函数报错
  3. 网站改版后确保无误才能上线!
  4. 服务器线程数一直增加,.NET Core中遇到奇怪的线程死锁问题:内存与线程数不停地增长...
  5. 在Hibernate的session中同时有两个相同id的同类型对象,修改失败
  6. 【转】ABP源码分析二十:ApplicationService
  7. Go语言并发编程简介
  8. C语言之运算符优先级(四十二)
  9. Lightroom Classic教程:如何显示堆叠?
  10. Ubuntu配置NFS服务器与客户端
  11. js从服务器获取word文档,JavaScript-js如何获取word文档页数
  12. 一种基于定时任务检测物联网设备异常状态的方法
  13. 中国区块链市场被低估?谈谈那些被低估的虚拟货币
  14. 2015年移动Web/HybridApp开发技能列表
  15. 通过js实现单击显示隐藏图片
  16. 【python】OCR
  17. 视频教程-新版华为HCIA数通(路由与交换)课程-华为认证
  18. JAVA学习路线图 【黑马版】
  19. SpringBoot之自动装配原理
  20. (一)高德地图之基本属性以及显示模式

热门文章

  1. 向Excel中批量插入图片,自动排版
  2. 12306排队是什么意思_12306 说:有时候,能排队也是一种幸福!
  3. 华科计算机博导刘云生论文,华科白翔老师团队ECCV2018 OCR论文:Mask TextSpotter
  4. iphone文件app里无法连接服务器,苹果商店怎么打不开 无法连接到app store解决方法...
  5. 推荐 | 一些奇特的人工智能App
  6. 案例详解-如何在 Linux 系统中安装和使用 7zip 以及 7zip的脚本编程使用教程(非p7zip,而是官方版本7zip for linux)附deb包下载链接
  7. uniapp 车牌号输入 车牌号键盘 新能源车牌键盘 特殊车辆车牌键盘
  8. 安装 SuMa (Surfel-based Mapping using 3D Laser Range Data)遇到的问题
  9. Python笔记-上证指数收益率计算
  10. 才茂CM520如何通过4G物联网卡将信号发送到PC端