- 积分
- 36110
- 明经币
- 个
- 注册时间
- 2006-12-16
- 在线时间
- 小时
- 威望
-
- 金钱
- 个
- 贡献
-
- 激情
-
|
本帖最后由 qjchen 于 2013-10-20 19:28 编辑
其实两三年前就有这个想法了,当时学flex编程的时候,找到了BOX2D库,觉得很有趣
那时只是简单测试了一下flash的box2d库,没有仔细学习。愤怒的小鸟也还没有出来。后来有了,知道它也是用了这个库,但是和box2d库的作者弄的不可开交。
由于个人比较喜欢autocad,所以比较想在cad中实现。但当时的BOX2D库还只有c++版,不大懂。这几天稍有空,随手找了几个物理引擎库,发现已经有人port到了.net版,于是重燃了此番昔日思路。花了2天时间,利用box2d引擎,撰写了如下这个多线程版本的 Autocad 版的 愤怒的小鸟。可以一边玩,一边画图。纯属自娱自乐。 此.NET引擎似乎还有一些小问题,比如圆形似乎就没有rotation特性(或者是我还没有发现),时间间隔亦宜小些,否则会出现一些侵蚀现象(当然,后期会调整过来)。
本文只提供cad部分的代码,BOX2DX的由于不是我编的,自然不能放上来 由于只是一个娱乐自玩小程序,故没有太多的容错内容,也没考虑多少种情况,大概能用而已。
测试的dwg可见附件。 使用方法: 1. 打开dwg 2. 编译代码到DLL,另外编译下载的BOX2DX得到BOX2DX.DLL,Netload这两个ball.dll 需要注意的是,在编译用于高版本ACAD的BOX2DX.DLL的时候,需要将其编译平台设为any cpu 3. 用mybox2d命令启动,选择不可移动物体,选择可移动物体,选择可发射物体(力在此图中建议为120000) 4. 要结束这个动态过程,请键入mys结束之,也一定在关闭cad前运行此命令
// ========================================================================
// The following codes are writen by QJCHEN ;
// Http://qjchen.mjtd.com ;
// Important: Box2d Library is necessary to support this code ;
// http://code.google.com/p/box2dx/ ;
// You should download it to generate Box2DX.dll first ;
// then you could use this code ;
// Purpose: Test angry bird in Autocad ;
// How to use: ;
// 1) open the dwg in the attachment ;
// 2) netload Box2DX and this dll (compile this code to DLL) ;
// 3) command mybox2d, then select the object for fix object(circle or ;
// lwpolyline), moving object, and ejecting object (these two is block ;
// reference, I have make several one, such as 1*1 box, R=0.5 circle, ;
// then use different scalefactor to insert them). Then input the force;
// because the unit of these world is (N, m), so it need a big force ;
// in this jpg, the force is 120000 ;
// 4) Use mys command to stop the game ;
// The platform: Acad2008 and after ;
// .Net platform is considered to be a better solution for this function ;
// Version: 1.0 ;
// 2013.01.28 ;
// Thanks to Gile's function for judging the direction of lwpolyline ;
// ========================================================================
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using System;
using System.Collections;
using Box2DX.Dynamics;
using Box2DX.Collision;
using Box2DX.Common;
//gile's function
using Body = Box2DX.Dynamics.Body;
using aapp = Autodesk.AutoCAD.ApplicationServices.Application;
using sm = System.Math;
namespace ball
{
public class Class1
{
public static ObjectIdCollection mBodyId;//能移动的所有物体的id Moving objects IDs
public static ObjectIdCollection eBodyId;//能有初速度的所有物体的id Ejecting objects IDs
public static World world;
public static float timeStep = 1.0f / 60.0f;
public static int velocityIterations = 8;
public static int positionIterations = 1;
public static Body body;
public static Body[] mbody;
public static Body[] ebody;
static System.Windows.Forms.Timer timer2 = new System.Windows.Forms.Timer();
// 停止的命令
[CommandMethod("mys")]
public void drawpics()
{
timer2.Stop();
}
[CommandMethod("mybox2d")]
public void test()
{
//世界的定义,只在其中是有用的,定义在-100到100的高度范围内
//World of Box2d, -100 to 100
AABB worldAABB = new AABB();
worldAABB.LowerBound.Set(-100.0f);
worldAABB.UpperBound.Set(100.0f);
Vec2 gravity = new Vec2(0.0f, -10.0f);// Define the gravity vector.
bool doSleep = true;// Do we want to let bodies sleep?
world = new World(worldAABB, gravity, doSleep);// Construct a world object, which will hold and simulate the rigid bodies.
//--选择物体分别作为刚体和可移动物体
//--Select Object for Each group
SelectForFixBody();
SelectForMovingBody();
SelectForEjectingBody();
//--设置时间 Time setting
timer2.Interval = 20;//设置时间为20秒-这个和动画间隔相关
timer2.Tick += new EventHandler(timer2_Tick);
timer2.Start();
}
private static void timer2_Tick(System.Object myObject, System.EventArgs myEventArgs)
{
DocumentLock docLock = aapp.DocumentManager.MdiActiveDocument.LockDocument(); // Code
world.Step(timeStep, velocityIterations, positionIterations);
//对每一个可移动的物体进行更新 Update for moving objects
int i = 0;
foreach (ObjectId id in mBodyId)
{
Vec2 position = mbody.GetPosition();
float angle = mbody.GetAngle();
ChangeBlockRefInsPointAndAngle(id, new Point3d(position.X, position.Y, 0), angle);
i = i + 1;
}
//Update for ejecting objects
i = 0;
foreach (ObjectId id in eBodyId)
{
Vec2 position = ebody.GetPosition();
float angle = ebody.GetAngle();
ChangeBlockRefInsPointAndAngle(id, new Point3d(position.X, position.Y, 0), angle);
i = i + 1;
}
docLock.Dispose();
}
//选择刚性不动物体,(必须是封闭的多义线-即用c进行闭合的多义线),否则会出错
//Select Fixed Object(Circle or closed lwpolyline)
public static ArrayList SelectForFixBody()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
ArrayList res = new ArrayList();
using (Transaction trans = db.TransactionManager.StartTransaction())
{
PromptSelectionOptions acOptSel = new PromptSelectionOptions();
acOptSel.MessageForAdding = "\n请选择不可移动物体(Please select the fixed object):";
// Create a TypedValue array to define the filter criteria
TypedValue[] acTypValAr = new TypedValue[1];
acTypValAr.SetValue(new TypedValue((int)DxfCode.Start, "LWPOLYLINE,CIRCLE"), 0);
// Assign the filter criteria to a SelectionFilter object
SelectionFilter acSelFtr = new SelectionFilter(acTypValAr);
PromptSelectionResult acSSPrompt = ed.GetSelection(acOptSel, acSelFtr);
if (acSSPrompt.Status == PromptStatus.OK)
{
SelectionSet acSSet = acSSPrompt.Value;
foreach (SelectedObject acSSObj in acSSet)
{
if (acSSObj != null)
{
Entity acEnt = trans.GetObject(acSSObj.ObjectId, OpenMode.ForWrite) as Entity;
if (acEnt != null)
{
ObjectId ObjID = acEnt.ObjectId;
BodyDef groundBodyDef = new BodyDef();
Entity ent0 = (Entity)trans.GetObject(ObjID, OpenMode.ForRead, false);
if (ent0.GetType().Name == "Circle")
{
Circle ent = (Circle)trans.GetObject(ObjID, OpenMode.ForRead, false);
Point3d cen = ent.Center;
//----定义不可移动物体,默认属性
groundBodyDef.Position.Set((float)cen.X, (float)cen.Y);
Body groundBody = world.CreateBody(groundBodyDef);
CircleDef groundShapeDef = new CircleDef();
groundShapeDef.Radius = (float)ent.Radius;
groundBody.CreateFixture(groundShapeDef);
res.Add(groundBody);
}
else if (ent0.GetType().Name == "Polyline")
{
Polyline ent = (Polyline)trans.GetObject(ObjID, OpenMode.ForRead, false);
Point2d v0 = ent.GetPoint2dAt(0);
Vec2[] plvex = GetPolylineForBox2d(ent);
//----定义不可移动物体,默认属性
groundBodyDef.Position.Set((float)v0.X, (float)v0.Y);
Body groundBody = world.CreateBody(groundBodyDef);
PolygonDef groundShapeDef = new PolygonDef();
groundShapeDef.VertexCount = plvex.Length;
groundShapeDef.Vertices = plvex;
groundBody.CreateFixture(groundShapeDef);
res.Add(groundBody);
}
}
}
}
trans.Commit();
}
return res;
}
}
//选择可发射物体,必须是矩形或圆形的块,否则会出错
//Select Ejecting Object, Should be rectangle of circle Block
public static ArrayList SelectForEjectingBody()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
ArrayList res = new ArrayList();
eBodyId = new ObjectIdCollection();
using (Transaction trans = db.TransactionManager.StartTransaction())
{
// Create a TypedValue array to define the filter criteria
TypedValue[] acTypValAr = new TypedValue[1];
acTypValAr.SetValue(new TypedValue((int)DxfCode.Start, "INSERT"), 0);
SelectionFilter acSelFtr = new SelectionFilter(acTypValAr);
PromptSelectionOptions acOptSel = new PromptSelectionOptions();
acOptSel.MessageForAdding = "\n----\n请选择可发射物体(Please select ejecting object):";
PromptSelectionResult acSSPrompt = ed.GetSelection(acOptSel, acSelFtr);
PromptStringOptions pStrOpts = new PromptStringOptions("\n输入X水平力(Input the X force):(100000)N:");
pStrOpts.AllowSpaces = true;
PromptResult pStrRes = ed.GetString(pStrOpts);
float forcex = System.Convert.ToSingle(pStrRes.StringResult);
pStrOpts = new PromptStringOptions("\n输入Y水平力(Input the Y force):(100000)N:");
pStrOpts.AllowSpaces = true;
pStrRes = ed.GetString(pStrOpts);
float forcey = System.Convert.ToSingle(pStrRes.StringResult);
Vec2 force = new Vec2(forcex, forcey);
if (acSSPrompt.Status == PromptStatus.OK)
{
SelectionSet acSSet = acSSPrompt.Value;
ebody = new Body[acSSet.Count];
int i = 0;
foreach (SelectedObject acSSObj in acSSet)
{
if (acSSObj != null)
{
Entity acEnt = trans.GetObject(acSSObj.ObjectId, OpenMode.ForWrite) as Entity;
if (acEnt != null)
{
var blkRef = trans.GetObject(acSSObj.ObjectId, OpenMode.ForWrite, false) as BlockReference;
float dx = (float)blkRef.ScaleFactors.X;
float dy = (float)blkRef.ScaleFactors.Y;
float rotation = (float)blkRef.Rotation;
Point3d cen = blkRef.Position;
//只考虑方形和圆形两种物体
//-----定义可移动物体,随便定义的属性
BodyDef BodyDef = new BodyDef();
BodyDef.Position.Set((float)cen.X, (float)cen.Y);
Body eBodyi = world.CreateBody(BodyDef);
Point3d respt = GetCircleInBlockReference(acSSObj.ObjectId);
if (respt != Point3d.Origin)
{
CircleDef eShapeDef = new CircleDef();
eShapeDef.Radius = dx / 2.0f;
eShapeDef.Density = 1.0f;// Set the box density to be non-zero, so it will be dynamic.
eShapeDef.Restitution = 0.35f;//这个是反弹的控制(0-1)
eShapeDef.Friction = 0.25f;// Override the default friction.
eBodyi.CreateFixture(eShapeDef);// Add the shape to the body.
eBodyi.SetMassFromShapes();
eBodyi.SetAngle(rotation);
Vec2 forceP = new Vec2((float)cen.X, (float)cen.Y);
eBodyi.ApplyForce(force, eBodyi.GetWorldCenter());
ebody = eBodyi;
eBodyId.Add(acSSObj.ObjectId);
}
else
{
PolygonDef eShapeDef = new PolygonDef();
eShapeDef.SetAsBox(dx / 2.0f, dy / 2.0f);
eShapeDef.VertexCount = 4;
eShapeDef.Density = 1.0f;// Set the box density to be non-zero, so it will be dynamic.
eShapeDef.Restitution = 0.35f;//这个是反弹的控制(0-1),不知道只设置一个有没有效果
eShapeDef.Friction = 0.25f;// Override the default friction.
eBodyi.CreateFixture(eShapeDef);// Add the shape to the body.
eBodyi.SetMassFromShapes();
eBodyi.SetAngle(rotation);
eBodyi.ApplyForce(force, eBodyi.GetWorldCenter());
ebody = eBodyi;
eBodyId.Add(acSSObj.ObjectId);
}
}
}
i++;
}
}
trans.Commit();
}
return res;
}
//选择可掉下物体,必须是矩形或圆形的块,否则会出错
//Select Moving Object, Should be rectangle of circle Block
public static ArrayList SelectForMovingBody()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
ArrayList res = new ArrayList();
mBodyId = new ObjectIdCollection();
using (Transaction trans = db.TransactionManager.StartTransaction())
{
// Create a TypedValue array to define the filter criteria
TypedValue[] acTypValAr = new TypedValue[1];
acTypValAr.SetValue(new TypedValue((int)DxfCode.Start, "INSERT"), 0);
SelectionFilter acSelFtr = new SelectionFilter(acTypValAr);
PromptSelectionOptions acOptSel = new PromptSelectionOptions();
acOptSel.MessageForAdding = "\n----\n请选择可移动物体(Please select Moving object):";
PromptSelectionResult acSSPrompt = ed.GetSelection(acOptSel, acSelFtr);
if (acSSPrompt.Status == PromptStatus.OK)
{
SelectionSet acSSet = acSSPrompt.Value;
mbody = new Body[acSSet.Count];
int i = 0;
foreach (SelectedObject acSSObj in acSSet)
{
if (acSSObj != null)
{
Entity acEnt = trans.GetObject(acSSObj.ObjectId, OpenMode.ForWrite) as Entity;
if (acEnt != null)
{
var blkRef = trans.GetObject(acSSObj.ObjectId, OpenMode.ForWrite, false) as BlockReference;
float dx = (float)blkRef.ScaleFactors.X;
float dy = (float)blkRef.ScaleFactors.Y;
float rotation = (float)blkRef.Rotation;
Point3d cen = blkRef.Position;
//只考虑方形和圆形两种物体
//-----定义可移动物体,随便定义的属性
BodyDef BodyDef = new BodyDef();
BodyDef.Position.Set((float)cen.X, (float)cen.Y);
Body mBodyi = world.CreateBody(BodyDef);
Point3d respt = GetCircleInBlockReference(acSSObj.ObjectId);
if (respt != Point3d.Origin)
{
CircleDef mShapeDef = new CircleDef();
mShapeDef.Radius = dx / 2.0f;
mShapeDef.Density = 1.0f;// Set the box density to be non-zero, so it will be dynamic.
mShapeDef.Restitution = 0.35f;//这个是反弹的控制(0-1),不知道只设置一个有没有效果
mShapeDef.Friction = 0.25f;// Override the default friction.
mBodyi.CreateFixture(mShapeDef);// Add the shape to the body.
mBodyi.SetMassFromShapes();
mBodyi.SetAngle(rotation);
mbody = mBodyi;
mBodyId.Add(acSSObj.ObjectId);
}
else
{
PolygonDef mShapeDef = new PolygonDef();
//Vec2[] plvex = ChangeBox2Poly(dx, dy, rotation);
mShapeDef.SetAsBox(dx / 2.0f, dy / 2.0f);
mShapeDef.VertexCount = 4;
//mShapeDef.Vertices = plvex;
mShapeDef.Density = 1.0f;// Set the box density to be non-zero, so it will be dynamic.
mShapeDef.Restitution = 0.35f;//这个是反弹的控制(0-1),不知道只设置一个有没有效果
mShapeDef.Friction = 0.25f;// Override the default friction.
mBodyi.CreateFixture(mShapeDef);// Add the shape to the body.
mBodyi.SetMassFromShapes();
mBodyi.SetAngle(rotation);
mbody = mBodyi;
mBodyId.Add(acSSObj.ObjectId);
}
}
}
i++;
}
}
trans.Commit();
}
return res;
}
//改变块的插入点和方向
//Change the insertion point and direction of block reference
public static void ChangeBlockRefInsPointAndAngle(ObjectId BlockRefId, Point3d newposition, float angle)
{
Database db = HostApplicationServices.WorkingDatabase;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
Entity ent = (Entity)tr.GetObject(BlockRefId, OpenMode.ForWrite);
var blkRef = tr.GetObject(BlockRefId, OpenMode.ForWrite, false) as BlockReference;
blkRef.Position = newposition;
blkRef.Rotation = angle;
tr.Commit();
Autodesk.AutoCAD.ApplicationServices.Application.UpdateScreen();
}
}
// Get some circle information in a block reference
public static Point3d GetCircleInBlockReference(ObjectId oId)
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Point3d pt = new Point3d();
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockReference bref = tr.GetObject(oId, OpenMode.ForRead) as BlockReference;
BlockTableRecord btr = tr.GetObject(bref.BlockTableRecord, OpenMode.ForRead) as BlockTableRecord;
foreach (ObjectId id in btr)
{
Circle cir = tr.GetObject(id, OpenMode.ForRead) as Circle;
if (cir != null)
{
pt = cir.Center.TransformBy(bref.BlockTransform);
}
}
}
return pt;
}
//Get lwPolyline information for drawing fixed object
public static Vec2[] GetPolylineForBox2d(Polyline pl)
{
Point2d P0 = pl.GetPoint2dAt(0);
Vec2[] res = new Vec2[pl.NumberOfVertices];
Point3d P03d = new Point3d(pl.GetPoint2dAt(0).X, pl.GetPoint2dAt(0).Y, 0);
Point3d P13d = new Point3d(pl.GetPoint2dAt(1).X, pl.GetPoint2dAt(1).Y, 0);
Point3d P23d = new Point3d(pl.GetPoint2dAt(2).X, pl.GetPoint2dAt(2).Y, 0);
Vector3d normal = new Vector3d(0, 0, 1);
int judge = Clockwise(P03d, P13d, P23d, normal);
Point2d Pti = new Point2d();
for (int i = 0; i < pl.NumberOfVertices; i++)
{
if (judge == -1)
{ Pti = pl.GetPoint2dAt(i); }
else
{ Pti = pl.GetPoint2dAt(pl.NumberOfVertices - 1 - i); }
Vec2 resi = new Vec2((float)(Pti.X - P0.X), (float)(Pti.Y - P0.Y));
res = resi;
}
return res;
}
//gile's function http://www.theswamp.org/index.php?topic=30428.msg360469#msg360469
// Clockwise method, returns 1 if p1, p2, p3 are clockwise,
// 0 if they're aligned, -1 if they're counterclockwise
public static int Clockwise(Point3d p1, Point3d p2, Point3d p3, Vector3d normal)
{
const double pi = 3.141592653589793;
Vector3d v1 = p1.GetVectorTo(p2);
Vector3d v2 = p1.GetVectorTo(p3);
double angle = v1.GetAngleTo(v2, normal);
if (angle == 0.0 || angle == pi)
return 0;
else
{
if (v1.GetAngleTo(v2, normal) < pi)
return -1;
else
return 1;
}
}
}
}
// ========================================================================
// The following codes are writen by QJCHEN ;
// Http://qjchen.mjtd.com ;
// Important: Box2d Library is necessary to support this code ;
// http://code.google.com/p/box2dx/ ;
// You should download it to generate Box2DX.dll first ;
// then you could use this code ;
// Purpose: Test angry bird in Autocad ;
// How to use: ;
// 1) open the dwg in the attachment ;
// 2) netload Box2DX and this dll (compile this code to DLL) ;
// 3) command mybox2d, then select the object for fix object(circle or ;
// lwpolyline), moving object, and ejecting object (these two is block ;
// reference, I have make several one, such as 1*1 box, R=0.5 circle, ;
// then use different scalefactor to insert them). Then input the force;
// because the unit of these world is (N, m), so it need a big force ;
// in this jpg, the force is 120000 ;
// 4) Use mys command to stop the game ;
// The platform: Acad2008 and after ;
// .Net platform is considered to be a better solution for this function ;
// Version: 1.0 ;
// 2013.01.28 ;
// Thanks to Gile's function for judging the direction of lwpolyline ;
// ========================================================================
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using System;
using System.Collections;
using Box2DX.Dynamics;
using Box2DX.Collision;
using Box2DX.Common;
//gile's function
using Body = Box2DX.Dynamics.Body;
using aapp = Autodesk.AutoCAD.ApplicationServices.Application;
using sm = System.Math;
namespace ball
{
public class Class1
{
public static ObjectIdCollection mBodyId;//能移动的所有物体的id Moving objects IDs
public static ObjectIdCollection eBodyId;//能有初速度的所有物体的id Ejecting objects IDs
public static World world;
public static float timeStep = 1.0f / 60.0f;
public static int velocityIterations = 8;
public static int positionIterations = 1;
public static Body body;
public static Body[] mbody;
public static Body[] ebody;
static System.Windows.Forms.Timer timer2 = new System.Windows.Forms.Timer();
// 停止的命令
[CommandMethod("mys")]
public void drawpics()
{
timer2.Stop();
}
[CommandMethod("mybox2d")]
public void test()
{
//世界的定义,只在其中是有用的,定义在-100到100的高度范围内
//World of Box2d, -100 to 100
AABB worldAABB = new AABB();
worldAABB.LowerBound.Set(-100.0f);
worldAABB.UpperBound.Set(100.0f);
Vec2 gravity = new Vec2(0.0f, -10.0f);// Define the gravity vector.
bool doSleep = true;// Do we want to let bodies sleep?
world = new World(worldAABB, gravity, doSleep);// Construct a world object, which will hold and simulate the rigid bodies.
//--选择物体分别作为刚体和可移动物体
//--Select Object for Each group
SelectForFixBody();
SelectForMovingBody();
SelectForEjectingBody();
//--设置时间 Time setting
timer2.Interval = 20;//设置时间为20秒-这个和动画间隔相关
timer2.Tick += new EventHandler(timer2_Tick);
timer2.Start();
}
private static void timer2_Tick(System.Object myObject, System.EventArgs myEventArgs)
{
DocumentLock docLock = aapp.DocumentManager.MdiActiveDocument.LockDocument(); // Code
world.Step(timeStep, velocityIterations, positionIterations);
//对每一个可移动的物体进行更新 Update for moving objects
int i = 0;
foreach (ObjectId id in mBodyId)
{
Vec2 position = mbody.GetPosition();
float angle = mbody.GetAngle();
ChangeBlockRefInsPointAndAngle(id, new Point3d(position.X, position.Y, 0), angle);
i = i + 1;
}
//Update for ejecting objects
i = 0;
foreach (ObjectId id in eBodyId)
{
Vec2 position = ebody.GetPosition();
float angle = ebody.GetAngle();
ChangeBlockRefInsPointAndAngle(id, new Point3d(position.X, position.Y, 0), angle);
i = i + 1;
}
docLock.Dispose();
}
//选择刚性不动物体,(必须是封闭的多义线-即用c进行闭合的多义线),否则会出错
//Select Fixed Object(Circle or closed lwpolyline)
public static ArrayList SelectForFixBody()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
ArrayList res = new ArrayList();
using (Transaction trans = db.TransactionManager.StartTransaction())
{
PromptSelectionOptions acOptSel = new PromptSelectionOptions();
acOptSel.MessageForAdding = "\n请选择不可移动物体(Please select the fixed object):";
// Create a TypedValue array to define the filter criteria
TypedValue[] acTypValAr = new TypedValue[1];
acTypValAr.SetValue(new TypedValue((int)DxfCode.Start, "LWPOLYLINE,CIRCLE"), 0);
// Assign the filter criteria to a SelectionFilter object
SelectionFilter acSelFtr = new SelectionFilter(acTypValAr);
PromptSelectionResult acSSPrompt = ed.GetSelection(acOptSel, acSelFtr);
if (acSSPrompt.Status == PromptStatus.OK)
{
SelectionSet acSSet = acSSPrompt.Value;
foreach (SelectedObject acSSObj in acSSet)
{
if (acSSObj != null)
{
Entity acEnt = trans.GetObject(acSSObj.ObjectId, OpenMode.ForWrite) as Entity;
if (acEnt != null)
{
ObjectId ObjID = acEnt.ObjectId;
BodyDef groundBodyDef = new BodyDef();
Entity ent0 = (Entity)trans.GetObject(ObjID, OpenMode.ForRead, false);
if (ent0.GetType().Name == "Circle")
{
Circle ent = (Circle)trans.GetObject(ObjID, OpenMode.ForRead, false);
Point3d cen = ent.Center;
//----定义不可移动物体,默认属性
groundBodyDef.Position.Set((float)cen.X, (float)cen.Y);
Body groundBody = world.CreateBody(groundBodyDef);
CircleDef groundShapeDef = new CircleDef();
groundShapeDef.Radius = (float)ent.Radius;
groundBody.CreateFixture(groundShapeDef);
res.Add(groundBody);
}
else if (ent0.GetType().Name == "Polyline")
{
Polyline ent = (Polyline)trans.GetObject(ObjID, OpenMode.ForRead, false);
Point2d v0 = ent.GetPoint2dAt(0);
Vec2[] plvex = GetPolylineForBox2d(ent);
//----定义不可移动物体,默认属性
groundBodyDef.Position.Set((float)v0.X, (float)v0.Y);
Body groundBody = world.CreateBody(groundBodyDef);
PolygonDef groundShapeDef = new PolygonDef();
groundShapeDef.VertexCount = plvex.Length;
groundShapeDef.Vertices = plvex;
groundBody.CreateFixture(groundShapeDef);
res.Add(groundBody);
}
}
}
}
trans.Commit();
}
return res;
}
}
//选择可发射物体,必须是矩形或圆形的块,否则会出错
//Select Ejecting Object, Should be rectangle of circle Block
public static ArrayList SelectForEjectingBody()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
ArrayList res = new ArrayList();
eBodyId = new ObjectIdCollection();
using (Transaction trans = db.TransactionManager.StartTransaction())
{
// Create a TypedValue array to define the filter criteria
TypedValue[] acTypValAr = new TypedValue[1];
acTypValAr.SetValue(new TypedValue((int)DxfCode.Start, "INSERT"), 0);
SelectionFilter acSelFtr = new SelectionFilter(acTypValAr);
PromptSelectionOptions acOptSel = new PromptSelectionOptions();
acOptSel.MessageForAdding = "\n----\n请选择可发射物体(Please select ejecting object):";
PromptSelectionResult acSSPrompt = ed.GetSelection(acOptSel, acSelFtr);
PromptStringOptions pStrOpts = new PromptStringOptions("\n输入X水平力(Input the X force):(100000)N:");
pStrOpts.AllowSpaces = true;
PromptResult pStrRes = ed.GetString(pStrOpts);
float forcex = System.Convert.ToSingle(pStrRes.StringResult);
pStrOpts = new PromptStringOptions("\n输入Y水平力(Input the Y force):(100000)N:");
pStrOpts.AllowSpaces = true;
pStrRes = ed.GetString(pStrOpts);
float forcey = System.Convert.ToSingle(pStrRes.StringResult);
Vec2 force = new Vec2(forcex, forcey);
if (acSSPrompt.Status == PromptStatus.OK)
{
SelectionSet acSSet = acSSPrompt.Value;
ebody = new Body[acSSet.Count];
int i = 0;
foreach (SelectedObject acSSObj in acSSet)
{
if (acSSObj != null)
{
Entity acEnt = trans.GetObject(acSSObj.ObjectId, OpenMode.ForWrite) as Entity;
if (acEnt != null)
{
var blkRef = trans.GetObject(acSSObj.ObjectId, OpenMode.ForWrite, false) as BlockReference;
float dx = (float)blkRef.ScaleFactors.X;
float dy = (float)blkRef.ScaleFactors.Y;
float rotation = (float)blkRef.Rotation;
Point3d cen = blkRef.Position;
//只考虑方形和圆形两种物体
//-----定义可移动物体,随便定义的属性
BodyDef BodyDef = new BodyDef();
BodyDef.Position.Set((float)cen.X, (float)cen.Y);
Body eBodyi = world.CreateBody(BodyDef);
Point3d respt = GetCircleInBlockReference(acSSObj.ObjectId);
if (respt != Point3d.Origin)
{
CircleDef eShapeDef = new CircleDef();
eShapeDef.Radius = dx / 2.0f;
eShapeDef.Density = 1.0f;// Set the box density to be non-zero, so it will be dynamic.
eShapeDef.Restitution = 0.35f;//这个是反弹的控制(0-1)
eShapeDef.Friction = 0.25f;// Override the default friction.
eBodyi.CreateFixture(eShapeDef);// Add the shape to the body.
eBodyi.SetMassFromShapes();
eBodyi.SetAngle(rotation);
Vec2 forceP = new Vec2((float)cen.X, (float)cen.Y);
eBodyi.ApplyForce(force, eBodyi.GetWorldCenter());
ebody = eBodyi;
eBodyId.Add(acSSObj.ObjectId);
}
else
{
PolygonDef eShapeDef = new PolygonDef();
eShapeDef.SetAsBox(dx / 2.0f, dy / 2.0f);
eShapeDef.VertexCount = 4;
eShapeDef.Density = 1.0f;// Set the box density to be non-zero, so it will be dynamic.
eShapeDef.Restitution = 0.35f;//这个是反弹的控制(0-1),不知道只设置一个有没有效果
eShapeDef.Friction = 0.25f;// Override the default friction.
eBodyi.CreateFixture(eShapeDef);// Add the shape to the body.
eBodyi.SetMassFromShapes();
eBodyi.SetAngle(rotation);
eBodyi.ApplyForce(force, eBodyi.GetWorldCenter());
ebody = eBodyi;
eBodyId.Add(acSSObj.ObjectId);
}
}
}
i++;
}
}
trans.Commit();
}
return res;
}
//选择可掉下物体,必须是矩形或圆形的块,否则会出错
//Select Moving Object, Should be rectangle of circle Block
public static ArrayList SelectForMovingBody()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
ArrayList res = new ArrayList();
mBodyId = new ObjectIdCollection();
using (Transaction trans = db.TransactionManager.StartTransaction())
{
// Create a TypedValue array to define the filter criteria
TypedValue[] acTypValAr = new TypedValue[1];
acTypValAr.SetValue(new TypedValue((int)DxfCode.Start, "INSERT"), 0);
SelectionFilter acSelFtr = new SelectionFilter(acTypValAr);
PromptSelectionOptions acOptSel = new PromptSelectionOptions();
acOptSel.MessageForAdding = "\n----\n请选择可移动物体(Please select Moving object):";
PromptSelectionResult acSSPrompt = ed.GetSelection(acOptSel, acSelFtr);
if (acSSPrompt.Status == PromptStatus.OK)
{
SelectionSet acSSet = acSSPrompt.Value;
mbody = new Body[acSSet.Count];
int i = 0;
foreach (SelectedObject acSSObj in acSSet)
{
if (acSSObj != null)
{
Entity acEnt = trans.GetObject(acSSObj.ObjectId, OpenMode.ForWrite) as Entity;
if (acEnt != null)
{
var blkRef = trans.GetObject(acSSObj.ObjectId, OpenMode.ForWrite, false) as BlockReference;
float dx = (float)blkRef.ScaleFactors.X;
float dy = (float)blkRef.ScaleFactors.Y;
float rotation = (float)blkRef.Rotation;
Point3d cen = blkRef.Position;
//只考虑方形和圆形两种物体
//-----定义可移动物体,随便定义的属性
BodyDef BodyDef = new BodyDef();
BodyDef.Position.Set((float)cen.X, (float)cen.Y);
Body mBodyi = world.CreateBody(BodyDef);
Point3d respt = GetCircleInBlockReference(acSSObj.ObjectId);
if (respt != Point3d.Origin)
{
CircleDef mShapeDef = new CircleDef();
mShapeDef.Radius = dx / 2.0f;
mShapeDef.Density = 1.0f;// Set the box density to be non-zero, so it will be dynamic.
mShapeDef.Restitution = 0.35f;//这个是反弹的控制(0-1),不知道只设置一个有没有效果
mShapeDef.Friction = 0.25f;// Override the default friction.
mBodyi.CreateFixture(mShapeDef);// Add the shape to the body.
mBodyi.SetMassFromShapes();
mBodyi.SetAngle(rotation);
mbody = mBodyi;
mBodyId.Add(acSSObj.ObjectId);
}
else
{
PolygonDef mShapeDef = new PolygonDef();
//Vec2[] plvex = ChangeBox2Poly(dx, dy, rotation);
mShapeDef.SetAsBox(dx / 2.0f, dy / 2.0f);
mShapeDef.VertexCount = 4;
//mShapeDef.Vertices = plvex;
mShapeDef.Density = 1.0f;// Set the box density to be non-zero, so it will be dynamic.
mShapeDef.Restitution = 0.35f;//这个是反弹的控制(0-1),不知道只设置一个有没有效果
mShapeDef.Friction = 0.25f;// Override the default friction.
mBodyi.CreateFixture(mShapeDef);// Add the shape to the body.
mBodyi.SetMassFromShapes();
mBodyi.SetAngle(rotation);
mbody = mBodyi;
mBodyId.Add(acSSObj.ObjectId);
}
}
}
i++;
}
}
trans.Commit();
}
return res;
}
//改变块的插入点和方向
//Change the insertion point and direction of block reference
public static void ChangeBlockRefInsPointAndAngle(ObjectId BlockRefId, Point3d newposition, float angle)
{
Database db = HostApplicationServices.WorkingDatabase;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
Entity ent = (Entity)tr.GetObject(BlockRefId, OpenMode.ForWrite);
var blkRef = tr.GetObject(BlockRefId, OpenMode.ForWrite, false) as BlockReference;
blkRef.Position = newposition;
blkRef.Rotation = angle;
tr.Commit();
Autodesk.AutoCAD.ApplicationServices.Application.UpdateScreen();
}
}
// Get some circle information in a block reference
public static Point3d GetCircleInBlockReference(ObjectId oId)
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Point3d pt = new Point3d();
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockReference bref = tr.GetObject(oId, OpenMode.ForRead) as BlockReference;
BlockTableRecord btr = tr.GetObject(bref.BlockTableRecord, OpenMode.ForRead) as BlockTableRecord;
foreach (ObjectId id in btr)
{
Circle cir = tr.GetObject(id, OpenMode.ForRead) as Circle;
if (cir != null)
{
pt = cir.Center.TransformBy(bref.BlockTransform);
}
}
}
return pt;
}
//Get lwPolyline information for drawing fixed object
public static Vec2[] GetPolylineForBox2d(Polyline pl)
{
Point2d P0 = pl.GetPoint2dAt(0);
Vec2[] res = new Vec2[pl.NumberOfVertices];
Point3d P03d = new Point3d(pl.GetPoint2dAt(0).X, pl.GetPoint2dAt(0).Y, 0);
Point3d P13d = new Point3d(pl.GetPoint2dAt(1).X, pl.GetPoint2dAt(1).Y, 0);
Point3d P23d = new Point3d(pl.GetPoint2dAt(2).X, pl.GetPoint2dAt(2).Y, 0);
Vector3d normal = new Vector3d(0, 0, 1);
int judge = Clockwise(P03d, P13d, P23d, normal);
Point2d Pti = new Point2d();
for (int i = 0; i < pl.NumberOfVertices; i++)
{
if (judge == -1)
{ Pti = pl.GetPoint2dAt(i); }
else
{ Pti = pl.GetPoint2dAt(pl.NumberOfVertices - 1 - i); }
Vec2 resi = new Vec2((float)(Pti.X - P0.X), (float)(Pti.Y - P0.Y));
res = resi;
}
return res;
}
//gile's function http://www.theswamp.org/index.php?topic=30428.msg360469#msg360469
// Clockwise method, returns 1 if p1, p2, p3 are clockwise,
// 0 if they're aligned, -1 if they're counterclockwise
public static int Clockwise(Point3d p1, Point3d p2, Point3d p3, Vector3d normal)
{
const double pi = 3.141592653589793;
Vector3d v1 = p1.GetVectorTo(p2);
Vector3d v2 = p1.GetVectorTo(p3);
double angle = v1.GetAngleTo(v2, normal);
if (angle == 0.0 || angle == pi)
return 0;
else
{
if (v1.GetAngleTo(v2, normal) < pi)
return -1;
else
return 1;
}
}
}
}
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?注册
x
评分
-
查看全部评分
|