TheSwamp
Code Red => .NET => Topic started by: Patch61 on March 25, 2011, 11:13:28 AM
-
I'm trying to write a routine that will insert a block (with attributes) in the current UCS. I have cobbled this together from a few different sources, but I can't quite get the orientation to work consistently. I've tried a couple different examples of TransformBy on the block, but neither works consistently correctly.
Any ideas?
Also... How do I exit cleanly? When I'm done with my routine, it leaves the command line in a state that is not ready (no prompt). I have to hit Esc or Enter to get back the command prompt.
Public Sub InsertDrawingAsBlock(ByVal doc As Document, ByVal path As String, ByVal blockname As String, _
ByVal iPt As Point3d, Optional ByVal Space As String = "Model", _
Optional ByVal LayerName As String = "Misc", Optional ByVal Xplode As Boolean = False, _
Optional ByVal bRotate As Double = 0.0, Optional ByVal bXScale As Single = 1.0, _
Optional ByVal bYScale As Single = 1.0, Optional ByVal bZScale As Single = 1.0)
Dim curdb As Database = doc.Database
Dim ed As Editor = doc.Editor
Dim loc As DocumentLock = doc.LockDocument()
Dim ucsMat As Matrix3d = ed.CurrentUserCoordinateSystem
Using loc
Dim blkid As ObjectId = ObjectId.Null
Dim db As New Database(False, True)
Using db
db.ReadDwgFile(path, System.IO.FileShare.Read, True, "")
blkid = curdb.Insert(path, db, True)
Using tr As Transaction = doc.TransactionManager.StartTransaction()
Dim btr As BlockTableRecord = DirectCast(curdb.CurrentSpaceId.GetObject(OpenMode.ForWrite), BlockTableRecord)
Dim bt As BlockTable = DirectCast(tr.GetObject(curdb.BlockTableId, OpenMode.ForRead), BlockTable)
If bt.Has(blockname) Then
Dim btrId As ObjectId = bt(blockname).GetObject(OpenMode.ForRead).ObjectId
btr.UpgradeOpen()
Dim bref As New BlockReference(iPt, btrId)
btr.AppendEntity(bref)
tr.AddNewlyCreatedDBObject(bref, True)
Else
bt.UpgradeOpen()
Dim btrec As BlockTableRecord = DirectCast(blkid.GetObject(OpenMode.ForRead), BlockTableRecord)
btrec.UpgradeOpen()
btrec.Name = blockname
btrec.DowngradeOpen()
Using btr
'iPt = iPt.TransformBy(ucsMat)
Using bref As New BlockReference(iPt, blkid)
Dim mat As Matrix3d = Matrix3d.Identity
bref.TransformBy(mat)
'bref.TransformBy(ucsMat)
'Rotate
bref.Rotation = bRotate * (Math.PI / 180)
'Scale factor
bref.ScaleFactors = New Scale3d(bXScale, bYScale, bZScale)
btr.AppendEntity(bref)
tr.AddNewlyCreatedDBObject(bref, True)
Using btAttRec As BlockTableRecord = DirectCast(bref.BlockTableRecord.GetObject(OpenMode.ForRead), BlockTableRecord)
Dim atcoll As Autodesk.AutoCAD.DatabaseServices.AttributeCollection = bref.AttributeCollection
For Each subid As ObjectId In btAttRec
Dim ent As Entity = DirectCast(subid.GetObject(OpenMode.ForRead), Entity)
Dim attDef As AttributeDefinition = TryCast(ent, AttributeDefinition)
If attDef IsNot Nothing Then
'ed.WriteMessage(vbLf & "Value: " + attDef.TextString)
Dim attRef As New AttributeReference()
attRef.SetPropertiesFrom(attDef)
attRef.Visible = attDef.Visible
attRef.SetAttributeFromBlock(attDef, bref.BlockTransform)
attRef.HorizontalMode = attDef.HorizontalMode
attRef.VerticalMode = attDef.VerticalMode
attRef.Rotation = attDef.Rotation
attRef.TextStyleId = attDef.TextStyleId
attRef.Position = attDef.Position + iPt.GetAsVector()
attRef.Tag = attDef.Tag
attRef.FieldLength = attDef.FieldLength
attRef.TextString = attDef.TextString
attRef.AdjustAlignment(curdb)
atcoll.AppendAttribute(attRef)
tr.AddNewlyCreatedDBObject(attRef, True)
End If
Next
End Using
bref.DowngradeOpen()
'Does it need to be exploded?
If Xplode = True Then
bref.ExplodeToOwnerSpace()
bref.Erase()
End If
End Using
End Using
btrec.DowngradeOpen()
bt.DowngradeOpen()
ed.Regen()
End If
tr.Commit()
End Using
End Using
End Using
End Sub
-
Try use wcs insertion point, something like
Dim doc As Document = Application.DocumentManager.MdiActiveDocument
Dim pt As Point3d = New Point3d(100, 100, 100)
Dim ed As Editor = doc.Editor
Dim mat As Matrix3d = ed.CurrentUserCoordinateSystem
Dim ucs As CoordinateSystem3d = mat.CoordinateSystem3d
Dim wcsmat As Matrix3d = _
Matrix3d.AlignCoordinateSystem(ucs.Origin, ucs.Xaxis, ucs.Yaxis, ucs.Zaxis, _
Point3d.Origin, Vector3d.XAxis, Vector3d.YAxis, Vector3d.ZAxis)
Dim inspt As Point3d = pt.TransformBy(wcsmat)
InsertDrawingAsBlock(doc, "C:\Test\blah.dwg", "newblock", inspt, , , , , , , )
-
Thanks for the reply and the help. I appreciate the effort!
However, from what I can tell, all that you are transforming into the UCS is the insertion point, not the inserted block. I'm trying to adapt what you posted into my program to transform the block reference, but I'm not having much luck.
It is still baffling to me that AutoDesk has done all this effort with their .Net API, but have totally missed the boat on useable documentation. So extremely far from a professional job that one is inclined to believe they are using the 'many monkees pounding keys for many days' method of documentation. Or perhaps, the person in charge of documentation is just plain stupid. Either scenario seems about as likely after trying to use the crap they shat on us.
Steve
-
However, from what I can tell, all that you are transforming into the UCS is the insertion point, not the inserted block. I'm trying to adapt what you posted into my program to transform the block reference, but I'm not having much luck.
Why would that be? You're already utilizing the TransformBy() method, just pass it an adaquate Matrix3d. Besides, the concept of combining transformations by multiplication of their matrices shouldn't be alien too.
Your other issue may be solved missing-prompt-wise by Autodesk.AutoCAD.Internal.Utils.PostCommandPrompt().
-
Patch 61,
What does this represent
ByVal iPt As Point3d
??
Is the variable holding a point in the current UCS or in WORLD (note that the current UCS may BE World).
Points selected by getpoint will be in the current UCS.
However, from what I can tell, all that you are transforming into the UCS is the insertion point, not the inserted block.
Your understanding is incorrect.
Fixo's code transforms the UCS defined pt to the WCS defined insPt
Then inserts the block at insPt.
-
addendum
Does this
Trying to insert block in current UCS.
actually mean you want to do this :
Insert a Block at a point defined in the current UCS ??
-
Does this
Trying to insert block in current UCS.
actually mean you want to do this :
Insert a Block at a point defined in the current UCS ??
I think he means:
Insert a block at a point defined in the current UCS and align it with the XY plane of the current UCS.
Discounting rotation and scaling, the transform could look like
db.GetUcsMatrix * Matrix3d.Displacement(iPt - Point3d.Origin)
The database extension was discussed recently http://www.theswamp.org/index.php?topic=37409.msg425283#msg425283 (http://www.theswamp.org/index.php?topic=37409.msg425283#msg425283),
selected earlier mentions are http://www.theswamp.org/index.php?topic=19035.msg231983#msg231983 (http://www.theswamp.org/index.php?topic=19035.msg231983#msg231983), http://www.theswamp.org/index.php?topic=20656.msg251052#msg251052 (http://www.theswamp.org/index.php?topic=20656.msg251052#msg251052) and way back in 2005 http://www.theswamp.org/index.php?topic=7657.msg97523#msg97523 (http://www.theswamp.org/index.php?topic=7657.msg97523#msg97523).
-
Does this
Trying to insert block in current UCS.
actually mean you want to do this :
Insert a Block at a point defined in the current UCS ??
I think he means:
Insert a block at a point defined in the current UCS and align it with the XY plane of the current UCS.
Discounting rotation and scaling, the transform could look like
db.GetUcsMatrix * Matrix3d.Displacement(iPt - Point3d.Origin)
The database extension was discussed recently http://www.theswamp.org/index.php?topic=37409.msg425283#msg425283 (http://www.theswamp.org/index.php?topic=37409.msg425283#msg425283),
selected earlier mentions are http://www.theswamp.org/index.php?topic=19035.msg231983#msg231983 (http://www.theswamp.org/index.php?topic=19035.msg231983#msg231983), http://www.theswamp.org/index.php?topic=20656.msg251052#msg251052 (http://www.theswamp.org/index.php?topic=20656.msg251052#msg251052) and way back in 2005 http://www.theswamp.org/index.php?topic=7657.msg97523#msg97523 (http://www.theswamp.org/index.php?topic=7657.msg97523#msg97523).
Yes, I want to take a user-clicked location and insert a block at that location, with the block being aligned to the current UCS, just like how the Insert command works in AutoCAD.
You guys have given me something new to try, so I will integrate your ideas with my code and see what we end up with. I've never completely understood matrix math... it hurts my brain!
Thanks for the help!
Steve
-
How would I use this in the context of my posted code? Is this returning a Matrix3D object?
db.GetUcsMatrix * Matrix3d.Displacement(iPt - Point3d.Origin)
Again, matrix math is greek to me. And the poor documentation from AutoDesk leaves me scratching my head on these issues. :|
Update:
When I try to use this as follows:
Dim UserMat As Matrix3d
UserMat = db.GetUcsMatrix * Matrix3d.Displacement(iPt - Point3d.Origin)
Visual Studio tells me that 'GetUcsMatrix' is not a member of 'AutoDesk.AutoCAD.DatabaseServices.Database'.
When I try to add the extension to my project, VS tells me 'Extension methods can be defined only in modules.' Huh? What modules? I'm working in VB, if that matters.
Ugh. I feel like a caveman trying to understand this. Inserting a block should be a simple thing. I hate this .Net API. :realmad:
Thanks,
Steve
-
Help! Please? Anybody? :cry:
-
I'll have a play tomorrow for you
.. but I do think you may have a little reading to do :)
-
I'll have a play tomorrow for you
.. but I do think you may have a little reading to do :)
Thanks, Kerry!
I don't mind reading and learning at all. Just, in this case, I have no clue what to read!
Steve
-
Hi,
Here's a little sample to insert a bloc in the current UCS.
EDIT there was something wrong in the precedent code.
This one is a little bit more explicit
[CommandMethod("TEST")]
public void InsertInCurrentUcs()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
PromptResult pr = ed.GetString("\nEnter the block name: ");
if (pr.Status != PromptStatus.OK)
return;
string bName = pr.StringResult;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
if (!bt.Has(bName))
{
ed.WriteMessage("\nCan't find '{0}' block.", bName);
return;
}
PromptPointResult ppr = ed.GetPoint("\nSpecify insertion point: ");
if (ppr.Status != PromptStatus.OK)
return;
// Get the current UCS Z axis (extrusion direction)
Matrix3d ucsMat = ed.CurrentUserCoordinateSystem;
CoordinateSystem3d ucs = ucsMat.CoordinateSystem3d;
Vector3d zdir = ucsMat.CoordinateSystem3d.Zaxis;
// Get the OCS corresponding to UCS Z axis
Matrix3d ocsMat = MakeOcs(zdir);
// Transform the input point from UCS to OCS
Point3d pt = ppr.Value.TransformBy(ucsMat.PreMultiplyBy(ocsMat));
// Get the X axis of the OCS
Vector3d ocsXdir = ocsMat.CoordinateSystem3d.Xaxis;
// Get the UCS rotation (angle between the OCS X axis and the UCS X axis)
double rot = ocsXdir.GetAngleTo(ucs.Xaxis, zdir);
BlockTableRecord btr =
(BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
BlockReference br = new BlockReference(pt, bt[bName]);
br.Position = pt;
br.Rotation = rot;
br.Normal = zdir;
btr.AppendEntity(br);
tr.AddNewlyCreatedDBObject(br, true);
tr.Commit();
}
}
// Return an OCS Matrix3d using the 'Arbitrary Axis Algoriythm'
private Matrix3d MakeOcs(Vector3d zdir)
{
double d = 1.0 / 64.0;
zdir = zdir.GetNormal();
Vector3d xdir = Math.Abs(zdir.X) < d && Math.Abs(zdir.Y) < d ?
Vector3d.YAxis.CrossProduct(zdir).GetNormal() :
Vector3d.ZAxis.CrossProduct(zdir).GetNormal();
Vector3d ydir = zdir.CrossProduct(xdir).GetNormal();
return new Matrix3d(new double[16]{
xdir.X, xdir.Y, xdir.Z, 0.0,
ydir.X, ydir.Y, ydir.Z, 0.0,
zdir.X, zdir.Y, zdir.Z, 0.0,
0.0, 0.0, 0.0, 1.0});
}
-
Here's a little sample to insert a bloc in the current UCS.
Okay, I'll bite. What do you win by transforming the insertion point only and do the calculation of the normal direction manually? I concede that it's always useful to have the know how to do it. Besides, there's little trick in your code: Setting the Position property isn't the same thing as calling the constructor with the insertion point.
Let's compare:
type acApp = Autodesk.AutoCAD.ApplicationServices.Application
type Database with
member db.IsPaperSpace =
if db.TileMode then false
else
let ed = acApp.DocumentManager.MdiActiveDocument.Editor
(db.PaperSpaceVportId = ed.CurrentViewportObjectId)
member db.GetUcsMatrix =
let (origin, xAxis, yAxis) =
if db.IsPaperSpace then
db.Pucsorg, db.Pucsxdir, db.Pucsydir
else
db.Ucsorg, db.Ucsxdir, db.Ucsydir
Matrix3d.AlignCoordinateSystem(
Point3d.Origin, Vector3d.XAxis, Vector3d.YAxis, Vector3d.ZAxis,
origin, xAxis, yAxis, xAxis.CrossProduct yAxis )
let myInsertUCS (tr: Transaction) _ (db: Database) (btrOid: ObjectId) (iPt: Point3d) =
let mat =
db.GetUcsMatrix *
Matrix3d.Displacement(iPt- Point3d.Origin)
let btr = tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) :?> BlockTableRecord
let bref = new BlockReference(Point3d.Origin, btrOid)
bref.TransformBy mat
btr.AppendEntity bref |> ignore
tr.AddNewlyCreatedDBObject(bref, true)
let gileInsertUCS (tr: Transaction) (ed: Editor) (db: Database) (btrOid: ObjectId) (iPt: Point3d) =
// Transform the input point from UCS to WCS
let ucsMat = ed.CurrentUserCoordinateSystem
let pt = iPt.TransformBy ucsMat
// Get the current UCS Z axis (extrusion direction)
let ucs = ucsMat.CoordinateSystem3d
let zdir = ucs.Zaxis
// Get the X axis of the OCS from the current UCS Z axis
// (using the 'Arbitrary Axis Algoriythm')
let d = 1.0 / 64.0
let ocsXdir =
if abs zdir.X < d && abs zdir.Y < d then
Vector3d.YAxis.CrossProduct zdir
else
Vector3d.ZAxis.CrossProduct zdir
// Get the UCS rotation (angle between the OCS X axis and the UCS X axis)
let rot = ocsXdir.GetAngleTo(ucs.Xaxis, zdir);
let btr = tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) :?> BlockTableRecord
let bref =
new BlockReference(
Point3d.Origin, btrOid,
Rotation = rot,
Normal = zdir,
Position = pt )
btr.AppendEntity bref |> ignore
tr.AddNewlyCreatedDBObject(bref, true)
let insertUCSCmd f =
let doc = acApp.DocumentManager.MdiActiveDocument
let db = doc.Database
let ed = doc.Editor
let pstr =
new PromptStringOptions(
"Block name",
AllowSpaces = true )
|> ed.GetString
if pstr.Status = PromptStatus.OK then
use tr = db.TransactionManager.StartTransaction()
let bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) :?> BlockTable
if not(bt.Has pstr.StringResult) then
ed.WriteMessage("\n{0} not defined. ", pstr.StringResult)
else
let ppr = ed.GetPoint("Insertion point")
if ppr.Status = PromptStatus.OK then
f tr ed db bt.[pstr.StringResult] ppr.Value
tr.Commit()
[<CommandMethod "myInsertUCS">]
let myInserUCSCmd() = insertUCSCmd myInsertUCS
[<CommandMethod "gileInsertUCS">]
let gileInserUCSCmd() = insertUCSCmd gileInsertUCS
-
You're right kaefer, I loose myself in the OCS route...
-
Thanks for the help, guys!
Kaefer,
What language is that? It's almost basic, but Visual Studio doesn't like it. :wink:
-
What language is that? It's almost basic, but Visual Studio doesn't like it.
It's F# and Visual Studio DO like it, it's part of Visual Studio 2010 and can be added to Visual Studio 2008 (not Express versions). See here (http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/release.aspx).
kaefer,
It seems that your 'db.GetUcsMatrix' function returns the same as the native ed.CurrentUserCoordinateSystem().
Here's a C# code using the 'righter way'.
[CommandMethod("TEST")]
public void InsertInCurrentUcs()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
PromptResult pr = ed.GetString("\nEnter the block name: ");
if (pr.Status != PromptStatus.OK)
return;
string bName = pr.StringResult;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
if (!bt.Has(bName))
{
ed.WriteMessage("\nCan't find '{0}' block.", bName);
return;
}
PromptPointResult ppr = ed.GetPoint("\nSpecify insertion point: ");
if (ppr.Status != PromptStatus.OK)
return;
Matrix3d ucsMat = ed.CurrentUserCoordinateSystem;
BlockTableRecord btr =
(BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
BlockReference br = new BlockReference(Point3d.Origin, bt[bName]);
br.TransformBy(ucsMat * Matrix3d.Displacement(ppr.Value - Point3d.Origin));
btr.AppendEntity(br);
tr.AddNewlyCreatedDBObject(br, true);
tr.Commit();
}
}
-
See here.
I assume that was supposed to be a link, but it's just bold. I have Visual Studio 2008 Standard.
-
Oopss !!!....
I add the link to the message, you can download F# 2.0 it will be added to VS standard.
-
kaefer,
It seems that your 'db.GetUcsMatrix' function returns the same as the native ed.CurrentUserCoordinateSystem().
Hi, gile.
Yeah, looks like it does. Wouldn't have thought that. Package label said:
Returns the current user coordinate system points.
Time to display a sheepish grin and stow away the much touted Database extension until there's no Editor to get a property of.
-
Thanks for the help, guys. I'll try the new code out as soon as I get a chance.
-
Gile,
I'm not having much luck integrating what you posted into the routine I posted. Some things just don't seem kosher. Like the Point3D.Origin you are using. Where is that from? I have the insertion point defined as iPt (using GetPoint), so I figured you meant to use that. But it won't let me use iPt.Origin, so I don't get what is going on. I guess if I knew enough to make your code work in my routine, I probably wouldn't have needed to ask for help in the first place.
Is there any chance you could slip your code into my routine? I need to insert a block from a file (checking to see if it already exists in the drawing) at the user-selected point, aligned with the current UCS. It also has to handle attributes.
I'm sure eventually this all will make sense, but right now, it doesn't. I feel like I am shooting in the dark here and I'm not hitting the target.
Thanks,
Steve
-
Point3d.Origin is a read-only Shared(static for you C#) property of the Point3d
gile's code
Dim ucsMatrix As Matrix3d = ed.CurrentUserCoordinateSystem
Dim bref As New BlockReference(Point3d.Origin)
bref.TransformBy(ucsMatrix * Matrix3d.Displacement(iPt - Point3d.Origin))
-
This is it from reflector
Public Shared ReadOnly Property Origin As Point3d
Get
Return New Point3d(0, 0, 0)
End Get
End Property
-
Point3d.Origin is a read-only Shared(static for you C#) property of the Point3d
gile's code
Dim ucsMatrix As Matrix3d = ed.CurrentUserCoordinateSystem
Dim bref As New BlockReference(Point3d.Origin)
bref.TransformBy(ucsMatrix * Matrix3d.Displacement(iPt - Point3d.Origin))
I understand what it is, I don't understand his use of a property of something that has not been assigned a value. That is why I asked where it is from. And, like I mentioned, I don't understand why it wouldn't let me use iPt.Origin in its place. I'm beginning to think I'm missing some basic thing here and that is causing me confusion.
-
Origin is a static (Shared) property of the Point3d class, that means it cannot be used with instances of this class.
Point3d.Origin is a kind of constant equivalent to : new Point3d(0.0, 0.0, 0.0).
In the code I posted (inspired by kaefer's one) the block reference is first inserted in 0, 0, 0 and then tranformed by a matix which is a combination of the UCS matrix and a displacement (vector) from 0, 0, 0 ti iPt so that the block refrence is rotate and displaced about the UCS and then displaced from the UCS origin to the specified insertion point.
-
Vb will let you use a shared a member with a instance of a the class it just generates a warning.
This will complie ans run but with warnings
Dim pointOrgin As New Point3d(0.0, 0.0, 0.0)
Dim pnt As Point3d = pointOrgin.Origin
Dim pointy As Point3d
Dim ucsMatrix As Matrix3d = ed.CurrentUserCoordinateSystem
Dim bref As New BlockReference(pointy.Origin, bt("BlockName"))
bref.TransformBy(ucsMatrix * Matrix3d.Displacement(pnt - pnt.Origin))
Each instance of the class does not get it own copy of a shared member. It is "class wide" or each instance "shares" hence Shared.
The property has been assinged and is assigned at the class level as read-only.
A good reason or example for using a shared property is to a count how many instances of a class have been created.
-
I think MS thinking is accessing a static property through the Class name instead of a instance makes your code harder to read, but in way a way is seems natural to be able to access it through a instance since it is meant to be "shared".
-
OK, no matter what I do, this is failing. It fails if the block exists, and it fails for a different reason if the block is loaded from disk. I don't know what I am doing wrong.
Public Sub InsertDrawingAsBlock(ByVal doc As Document, ByVal path As String, ByVal blockname As String, _
ByVal iPt As Point3d, Optional ByVal Space As String = "Model", _
Optional ByVal LayerName As String = "Misc", Optional ByVal Xplode As Boolean = False, _
Optional ByVal bRotate As Double = 0.0, Optional ByVal bXScale As Single = 1.0, _
Optional ByVal bYScale As Single = 1.0, Optional ByVal bZScale As Single = 1.0)
Dim curdb As Database = doc.Database
Dim ed As Editor = doc.Editor
Dim loc As DocumentLock = doc.LockDocument()
Using loc
Dim blkid As ObjectId = ObjectId.Null
Dim db As Database = doc.Database
Using db
db.ReadDwgFile(path, System.IO.FileShare.Read, True, "")
blkid = curdb.Insert(path, db, True)
Using tr As Transaction = db.TransactionManager.StartTransaction()
Dim bt As BlockTable = DirectCast(tr.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable)
Dim ucsMat As Matrix3d = ed.CurrentUserCoordinateSystem
Dim btr As BlockTableRecord = DirectCast(tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite), BlockTableRecord)
If bt.Has(blockname) Then
Dim br As New BlockReference(Point3d.Origin, bt(blockname))
br.TransformBy(ucsMat * Matrix3d.Displacement(iPt - Point3d.Origin))
Dim btrId As ObjectId = bt(blockname).GetObject(OpenMode.ForRead).ObjectId
btr.UpgradeOpen()
btr.AppendEntity(br)
tr.AddNewlyCreatedDBObject(br, True)
Else
bt.UpgradeOpen()
'Dim br As New BlockReference(Point3d.Origin, bt(blockname))
'br.TransformBy(ucsMat * Matrix3d.Displacement(iPt - Point3d.Origin))
Dim btrec As BlockTableRecord = DirectCast(blkid.GetObject(OpenMode.ForRead), BlockTableRecord)
btrec.UpgradeOpen()
btrec.Name = blockname
btrec.DowngradeOpen()
Using btr
Using bref As New BlockReference(iPt, blkid)
'Rotate 45 degrees
'45 * (Math.PI/180)
bref.Rotation = bRotate * (Math.PI / 180)
'Scale factor
bref.ScaleFactors = New Scale3d(bXScale, bYScale, bZScale)
bref.TransformBy(ucsMat * Matrix3d.Displacement(iPt - Point3d.Origin))
btr.AppendEntity(bref)
tr.AddNewlyCreatedDBObject(bref, True)
Using btAttRec As BlockTableRecord = DirectCast(bref.BlockTableRecord.GetObject(OpenMode.ForRead), BlockTableRecord)
Dim atcoll As Autodesk.AutoCAD.DatabaseServices.AttributeCollection = bref.AttributeCollection
For Each subid As ObjectId In btAttRec
Dim ent As Entity = DirectCast(subid.GetObject(OpenMode.ForRead), Entity)
Dim attDef As AttributeDefinition = TryCast(ent, AttributeDefinition)
If attDef IsNot Nothing Then
Dim attRef As New AttributeReference()
attRef.SetPropertiesFrom(attDef)
attRef.Visible = attDef.Visible
attRef.SetAttributeFromBlock(attDef, bref.BlockTransform)
attRef.HorizontalMode = attDef.HorizontalMode
attRef.VerticalMode = attDef.VerticalMode
attRef.Rotation = attDef.Rotation
attRef.TextStyleId = attDef.TextStyleId
attRef.Position = attDef.Position + iPt.GetAsVector()
attRef.Tag = attDef.Tag
attRef.FieldLength = attDef.FieldLength
attRef.TextString = attDef.TextString
attRef.AdjustAlignment(curdb)
atcoll.AppendAttribute(attRef)
tr.AddNewlyCreatedDBObject(attRef, True)
End If
Next
End Using
bref.DowngradeOpen()
'Does it need to be exploded?
If Xplode = True Then
bref.ExplodeToOwnerSpace()
bref.Erase()
End If
End Using
End Using
btrec.DowngradeOpen()
bt.DowngradeOpen()
ed.Regen()
End If
tr.Commit()
End Using
End Using
End Using
End Sub
-
Dim curdb As Database = doc.Database
Dim db As Database = doc.Database
Using db
db.ReadDwgFile(path, System.IO.FileShare.Read, True, "")
Just looking real quick you are using the same database from whatever doc is passed in as a parameter
You need to create a new database before you call ReadDwgFile
-
Don't make VB more verbose than it is:
Dim btrId As ObjectId = bt(blockname).GetObject(OpenMode.ForRead).ObjectId
is the same as:
Dim btrId As ObjectId = bt(blockname)
anyway, you can throw this expression as you never use btrId...
IMO, rather than trying to integrate the code I posted to yours, translate it to VB, try it, then add the features you want one by one, trying and debuging the code at each step.
-
By the name of your method I would assume you want insert another drawing as a block?
blkid = curdb.Insert(path, db, True)
Would you like to start fresh with option strict off so you do not need all the directcast?
-
Also ..
It may help if you included the sub/function that you are calling this from
... would make it so much easier to debug explicitly for your situation.
-
Option strict *is* off... Directcast is something I know NOTHING about, anyway. I got that from somebody's example or a conversion from C#.
I am hating .Net more and more. I used to love programming. Since .Net it has been headache after headache.
Here is the sub I am calling from (a button click - the BIC is a class that includes my block handling routines):
Private Sub cmdInsert_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdInsert.Click
'Dim InsStatus As Integer
Me.Hide()
Dim pPtRes As PromptPointResult
Dim pPtOpts As PromptPointOptions = New PromptPointOptions("")
Dim DWGname As String
Dim InsSpace As String = "Model"
Dim eXplode As Boolean = False
Dim InsLayer As String = "Misc"
Dim strTemp As String
Dim acDoc As Document = AcApp.DocumentManager.MdiActiveDocument
CurDWG = TreeView1.SelectedNode.Tag
DWGname = IO.Path.GetFileNameWithoutExtension(CurDWG)
If My.Computer.Keyboard.ShiftKeyDown Then
OpenFile(CurDWG, False)
Else
If VBStr.Right(DWGname, 3) = "-ps" Then
'DWGname = VBStr.Left(DWGname, Len(DWGname) - 3)
InsSpace = "Paper"
InsLayer = "Misc"
Else
' Determine Layer, Space, and eXplode
strTemp = VBStr.Left(VBStr.Right(DWGname, 6), 5)
If VBStr.Right(DWGname, 1) = "L" And IsNumeric(strTemp) Then
eXplode = True
End If
InsSpace = "Model"
InsLayer = "Misc"
strTemp = VBStr.Left(VBStr.Right(DWGname, 6), 5)
End If
ChangeSpace(InsSpace)
'Insert the drawing as a block
'' Prompt for the start point
pPtOpts.Message = vbLf & "Click where you wish to insert the block reference: "
pPtRes = CurDoc.Editor.GetPoint(pPtOpts)
Dim ptIns As Point3d = pPtRes.Value
'' Exit if the user presses ESC or cancels the command
If pPtRes.Status = PromptStatus.Cancel Then Exit Sub
LYR.SetLayerCurrent(InsLayer)
BIC.InsertDrawingAsBlock(CurDoc, CurDWG, DWGname, ptIns, InsSpace, InsLayer, eXplode)
End If
Autodesk.AutoCAD.Internal.Utils.PostCommandPrompt()
End Sub
-
I am hating .Net more and more. I used to love programming.
Take the LISP route...
-
I am hating .Net more and more. I used to love programming.
Take the LISP route...
Been there, done that. Have a U.S. Patent for artificially intelligent engineering software I wrote in Lisp.
I WILL NOT GO BACK!!!!
-
I do not see CurDoc declared, but who cares.
Would like to start off with a simple command to insert a external drawing and from that add options you want and tie in with your form or palette?
-
Dim curdb As Database = doc.Database
Dim db As Database = doc.Database
Using db
db.ReadDwgFile(path, System.IO.FileShare.Read, True, "")
Just looking real quick you are using the same database from whatever doc is passed in as a parameter
You need to create a new database before you call ReadDwgFile
Ok, I'm working on doing the 'reverse integration' as you suggested. One thing I don't get is the comment above. Why do I need to create a new database when, as in the above example, I just created one? That doesn't make any sense to me at all. I must be missing something here... again. :oops: And what does the doc passed to the routine have to do with it?
-
I do not see CurDoc declared, but who cares.
Would like to start off with a simple command to insert a external drawing and from that add options you want and tie in with your form or palette?
Yes, I would like to start off with a simple command to insert an external drawing. Right now, all I can do is copy what I have, which already has problems.
<rant>
The biggest problem I have with AutoCAD's .Net API is the very crappy documentation. This has to be the worst API documentation I've ever had to use. I've tried to look up how to insert a block and found nothing. Same for inserting a drawing as a block. Where are the step by step instructions? Where is the example? All I can find is technobabble that refers to other technobabble. It is only really useful if you already understand it.
</rant>
Thanks,
Steve
-
Sorry I have been busy or actually sleeping and hanging with kid I will post example later tonight with hopefully good enough notes to understand.
-
Steve,
Have a work through this.
It is a work in progress and have all your answers in due course.
http://www.theswamp.org/index.php?topic=37686.msg427185#new
-
As Kerry posted he has started a great thread that will help more than this.
Option strict *is* off... Directcast is something I know NOTHING about, anyway. I got that from somebody's example or a conversion from C#.
C# does not allow implicit conversion if it is a narrowing conversion. With VB if option strict is off it will allow a narrow conversion.
So using a tool to convert C# to VB can add DirectCast()-- which basically succeeds if the 2 types have a inheritance relationship and is more efficient than CType()
Why do I need to create a new database when, as in the above example, I just created one?
Not sure what new one was created? Both are assigned to the Database of the Document passed into your function.
Dim curdb As Database = doc.Database
Dim db As Database = doc.Database
Yes, I would like to start off with a simple command to insert an external drawing
This is copied from here http://forums.augi.com/showthread.php?t=126483
Hopefully if you have any questions someone will explain it to you.
Basically Insert a drawing as a block into current drawing then create and insert a new blockreference from it.
So please ask any questions if do not understand what the code is doing
<CommandMethod("InsertDwg")> _
Public Sub InsertDwg()
Dim doc As Document = Application.DocumentManager.MdiActiveDocument
Dim db As Database = doc.Database
Dim ed As Editor = doc.Editor
Dim fname As String = "C:\Users\Jeff\Documents\Drawing1.dwg"
Dim ObjId As ObjectId
Using trx As Transaction = db.TransactionManager.StartTransaction
Dim bt As BlockTable = db.BlockTableId.GetObject(OpenMode.ForRead)
Dim btrMs As BlockTableRecord = bt(BlockTableRecord.ModelSpace).GetObject(OpenMode.ForWrite)
Using dbInsert As New Database(False, True)
dbInsert.ReadDwgFile(fname, IO.FileShare.Read, True, "")
ObjId = db.Insert(Path.GetFileNameWithoutExtension(fname), dbInsert, True)
End Using
Dim ppo As New PromptPointOptions(vbCrLf & "Insertion Point")
Dim ppr As PromptPointResult
ppr = ed.GetPoint(ppo)
If ppr.Status <> PromptStatus.OK Then
ed.WriteMessage(vbCrLf & "You decided to QUIT!")
Exit Sub
End If
Dim insertPt As Point3d = ppr.Value
Dim bref As New BlockReference(insertPt, ObjId)
btrMs.AppendEntity(bref)
trx.AddNewlyCreatedDBObject(bref, True)
trx.Commit()
End Using
End Sub
-
Steve,
Have a work through this.
It is a work in progress and have all your answers in due course.
http://www.theswamp.org/index.php?topic=37686.msg427185#new
Kerry,
Great thread! It's a shame AutoDesk didn't give us anything like that, But I am soooo grateful for your assistance and sample code. If I could buy you a drink, I would.
Gile and JeffH,
Thanks for all your help and codes. I don't know what I would have done without your assistance (probably pulled out lots of my few remaining hairs).
You guys will be happy to know that my routine seems to be working and doing everything I need it to. Woot!
If either of you guys ever come to Orlando and want to see Disney, be sure to hit me up. My wife works there and we enjoy a number of perks from that and I wouldn't mind sharing (the perks, not my wife :-o :-D).
Thanks again, guys!
-
< .. > grateful for your assistance and sample code. If I could buy you a drink, I would.
< .. >
You're welcome Steve.
It's a bit far for me to travel to collect :-D
In the mean time, I know Mark would appreciate some monetary assistance to maintain the site so we can play here :).
Regards
-
Has anyone got the insert to work with a file that contains only xrefs? It does bring in the file, but in the xref manager all the xrefs are Unresolved. I am forced to right click in the status column and select Reload All References. I went through and debugged and it appears it is actually bring in the xrefs at this line. Could anyone give me some advice as to what I am missing. I'll post the entire code I am using.
ObjId = db.Insert(Path.GetFileNameWithoutExtension(fname), dbInsert, True)
<CommandMethod("ImportPart")> _
Public Sub ImportPart()
Dim fname As String = "R:\TEST\X-REF MASTER FILES\000022-01-01 TEST\000022-01-01 test drawing.dwg"
Dim doc As Document = Application.DocumentManager.MdiActiveDocument
Dim db As Database = doc.Database
Dim ed As Editor = doc.Editor
'Dim fname As String = "C:\Users\Jeff\Documents\Drawing1.dwg"
Dim ObjId As ObjectId
Using trx As Transaction = db.TransactionManager.StartTransaction
Using docLoc As DocumentLock = doc.LockDocument
Dim bt As BlockTable = db.BlockTableId.GetObject(OpenMode.ForRead)
Dim btrMs As BlockTableRecord = bt(BlockTableRecord.ModelSpace).GetObject(OpenMode.ForWrite)
Using dbInsert As New Database(False, True)
dbInsert.ReadDwgFile(fname, IO.FileShare.Read, False, "")
ObjId = db.Insert(Path.GetFileNameWithoutExtension(fname), dbInsert, True)
End Using
Dim ppo As New PromptPointOptions(vbCrLf & "Insertion Point")
Dim ppr As PromptPointResult
ppr = ed.GetPoint(ppo)
If ppr.Status <> PromptStatus.OK Then
ed.WriteMessage(vbCrLf & "You decided to QUIT!")
Exit Sub
End If
Dim insertPt As Point3d = ppr.Value
Dim bref As New BlockReference(insertPt, ObjId)
btrMs.AppendEntity(bref)
trx.AddNewlyCreatedDBObject(bref, True)
trx.Commit()
bref.ExplodeToOwnerSpace()
End Using
End Using
End If
Catch ex As Exception
End Try
End Sub
Thanks,
Ted
-
The exact same behavior happens if you do it through the UI.
Maybe call
Database.ReloadXrefs
-
Maybe call
Database.ReloadXrefs
Database.ReloadXrefs Method
Description
This function reloads the xrefs whose BlockTableRecord ObjectIds are in xrefIds
Database.ResolveXrefs Method
Description
This function resolves existing xrefs in the working database.
-
Thank you kaefer and Jeff! I modified my code to use Database.ResolveXrefs and it reloaded the new ones. Here is the new code.
<CommandMethod("ImportPart")> _
Public Sub ImportPart()
Dim fname As String = "R:\TEST\X-REF MASTER FILES\000022-01-01 TEST\000022-01-01 test drawing.dwg"
Dim doc As Document = Application.DocumentManager.MdiActiveDocument
Dim db As Database = doc.Database
Dim ed As Editor = doc.Editor
'Dim fname As String = "C:\Users\Jeff\Documents\Drawing1.dwg"
Dim ObjId As ObjectId
Using trx As Transaction = db.TransactionManager.StartTransaction
Using docLoc As DocumentLock = doc.LockDocument
Dim bt As BlockTable = db.BlockTableId.GetObject(OpenMode.ForRead)
Dim btrMs As BlockTableRecord = bt(BlockTableRecord.ModelSpace).GetObject(OpenMode.ForWrite)
Using dbInsert As New Database(False, True)
dbInsert.ReadDwgFile(fname, IO.FileShare.Read, False, "")
ObjId = db.Insert(Path.GetFileNameWithoutExtension(fname), dbInsert, True)
End Using
Dim ppo As New PromptPointOptions(vbCrLf & "Insertion Point")
Dim ppr As PromptPointResult
ppr = ed.GetPoint(ppo)
If ppr.Status <> PromptStatus.OK Then
ed.WriteMessage(vbCrLf & "You decided to QUIT!")
Exit Sub
End If
Dim insertPt As Point3d = ppr.Value
Dim bref As New BlockReference(insertPt, ObjId)
btrMs.AppendEntity(bref)
trx.AddNewlyCreatedDBObject(bref, True)
trx.Commit()
bref.ExplodeToOwnerSpace()
#############################
db.ResolveXrefs(False, False)
#############################
End Using
End Using
End If
Catch ex As Exception
End Try
End Sub