TheSwamp

Code Red => .NET => Topic started by: mohnston on January 04, 2007, 04:29:35 PM

Title: Copying plot settings
Post by: mohnston on January 04, 2007, 04:29:35 PM
I'm trying to copy plot settings from a drawing to use in a plotting program I am writing.

I get an AccessViolationException error "Attempted to read or write protected memory." when I run this code:
Code: [Select]
---------------------------------------
Database controlDB = new Database();
PlotSettings pSet = new PlotSettings(true);
PlotInfo pInf = new PlotInfo();
PlotSettingsValidator pValid = PlotSettingsValidator.Current;

controlDB.ReadDwgFile(plotControlDWG, System.IO.FileShare.Read, false, string.Empty);

Autodesk.AutoCAD.DatabaseServices.TransactionManager tm = controlDB.TransactionManager;
//controlDB.CloseInput(true);
Transaction trans = tm.StartTransaction();
try
{
DBDictionary dic = (DBDictionary)trans.GetObject(controlDB.PlotSettingsDictionaryId, OpenMode.ForRead);
foreach (DBDictionaryEntry dicEnt in dic)
{
if (dicEnt.Key == pgSetupName)
{
pSet = (PlotSettings)trans.GetObject(dicEnt.Value, OpenMode.ForRead, false);
}
}
trans.Commit();
}
finally { trans.Dispose(); }


pInf.Layout = LayoutManager.Current.GetLayoutId("Model");
pInf.OverrideSettings = pSet;
-------------------------

The error happens on this last line.
pSet is a valid PlotSettings. I see all the properties are set when I examine it.
pInf says that "Operation is not valid due to the current state of the object.". It reports this in the .DeviceOverride property which I am not setting.

Any idea why this is generating the error?
Has anyone done this successfully?
Title: Re: Copying plot settings
Post by: Kerry on January 04, 2007, 06:46:01 PM
Any chance of getting something closer to a 'workable'  class or method.
... would make any attempt to help a little easier .. :-)

eg:
where do these come from ?
plotControlDWG
pgSetupName

What are your special dependencies ?

Can we assume AC2007 ?
Title: Re: Copying plot settings
Post by: mohnston on January 04, 2007, 07:26:46 PM
AutoCAD 2007
Windows XP Pro
VS 2005

plotControlDWG is a string containing the full path to an existing drawing.
pgSetupName is a string containing the name of an existing Page Setup in the above drawing.

Dependencies are:
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.PlottingServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.ApplicationServices;

Thank you for your reply.
Title: Re: Copying plot settings
Post by: Kerry on January 04, 2007, 10:08:30 PM
Mark,

Don't have much spare time, but ..

this
Code: [Select]
        [CommandMethod("AsdkCmd1")]
        static public void test()
        {
            Database controlDB = new Database();
            PlotSettings pSet = new PlotSettings(true);
            PlotInfo pInf = new PlotInfo();
            PlotSettingsValidator pValid = PlotSettingsValidator.Current;
   
            string plotControlDWG = @"c:\Scripter.dwg";
            string pgSetupName = "CT1-A3MOD";

            controlDB.ReadDwgFile(plotControlDWG, System.IO.FileShare.Read, false, string.Empty);

            Autodesk.AutoCAD.DatabaseServices.TransactionManager tm = controlDB.TransactionManager;
            //controlDB.CloseInput(true);
            using (Transaction trans = tm.StartTransaction())
            {
                DBDictionary dic = (DBDictionary)trans.GetObject(controlDB.PlotSettingsDictionaryId, OpenMode.ForRead);
                foreach (DBDictionaryEntry dicEnt in dic)
                {
                    if (dicEnt.Key == pgSetupName)
                    {
                         pSet = (PlotSettings)trans.GetObject(dicEnt.Value, OpenMode.ForRead, false);
                    }
                }
                trans.Commit();
            }
            pInf.Layout = LayoutManager.Current.GetLayoutId("Model");
            pInf.OverrideSettings = pSet;

        }
produces a different exception at this line ;
Code: [Select]
pSet = (PlotSettings)trans.GetObject(dicEnt.Value, OpenMode.ForRead, false);
Code: [Select]
************** Exception Text **************
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> Autodesk.AutoCAD.Runtime.Exception: eDwgObjectImproperlyRead
   at Autodesk.AutoCAD.DatabaseServices.TransactionManager.GetObjectInternal(AcDbTransactionManager* pTM, ObjectId id, OpenMode mode, Boolean openErased, Boolean forceOpenOnLockedLayer)
   at Autodesk.AutoCAD.DatabaseServices.Transaction.GetObject(ObjectId id, OpenMode mode, Boolean openErased)
   at ClassLibrary.kdubTestClass.test() in K:\Visual Studio 2005 Projects\_CAD\CsMgdAcad-TestPlotConfig_01\CsMgdAcad-TestPlotConfig_01\Class.cs:line 105
   --- End of inner exception stack trace ---

perhaps something can be done with  pSet.CopyFrom( ... )  .. but thats a W.A.G.

I'll play some more if I get a chance.
/// kwb
Title: Re: Copying plot settings
Post by: It's Alive! on January 05, 2007, 12:31:08 AM
I don’t get any exceptions with the last code(but it does not work), I don’t know enough about Plot Settings to be of much help. I do have a couple of questions though.

Why is trans.Commit(); being called when nothing is being written to the database through the transaction manager (what are you committing to?) .

Which brings up my next question.

Of you need to open the source drawing’s database to get the plot setting
Wouldn’t you need to open the target drawing’s database (through the transaction manager) to write the new plot setting your copying?

Dan
Title: Re: Copying plot settings
Post by: Kerry on January 05, 2007, 12:53:44 AM
Quote
I don’t get any exceptions with the last code

Daniel,
When you changed these, does the template have the named setup you nominate ?
 
Code: [Select]
string plotControlDWG = @"c:\Scripter.dwg";
 string pgSetupName = "CT1-A3MOD";

Title: Re: Copying plot settings
Post by: Kerry on January 05, 2007, 01:07:05 AM
I believe you are correct about the redundancy of
trans.Commit();
 ... though I don't think it was catastrophic to leave it there :-)
Title: Re: Copying plot settings
Post by: Kerry on January 05, 2007, 01:11:12 AM
Quote
Wouldn’t you need to open the target drawing’s database (through the transaction manager) to write the new plot setting your copying?
At this stage I hadn't considered any further than collecting the information and getting past the exception that is being generated.

Quote
... I don’t know enough about Plot Settings ...
ditto, ditto, ditto ... black magic, as Glenn would say :lol:
Title: Re: Copying plot settings
Post by: It's Alive! on January 05, 2007, 01:26:04 AM
I did not get any execption if the source drawing "c:\Scripter.dwg" is closed.

Dan
Title: Re: Copying plot settings
Post by: Kerry on January 05, 2007, 01:44:07 AM
I did not get any execption if the source drawing "c:\Scripter.dwg" is closed.

Dan


I just looked ... I had no .dwl in the folder.  Looks like this is going to be one of those weird ones ... :lol:
Title: Re: Copying plot settings
Post by: It's Alive! on January 05, 2007, 03:54:41 AM
Hehe it looks that way. maybe my memory is not protected :)

 I added this line
Autodesk.AutoCAD.ApplicationServices.Application.ShowAlertDialog(pSet.PlotSettingsName);
And got

 
Cross posting is kind of like cross dressing, I really don’t care if you do it , but people might start to look at you funny
Title: Re: Copying plot settings
Post by: Kerry on January 05, 2007, 04:02:36 AM
expletive, big expletive, expletive

I think I WILL write that book ...
Title: Re: Copying plot settings
Post by: Kerry on January 05, 2007, 04:18:39 AM
Daniel. can you post your solution please
[ I'm clutching at straws here ]
.. you used my code, yes ?
This is SO bloody frustrating ... !!!
Title: Re: Copying plot settings
Post by: Glenn R on January 05, 2007, 08:19:11 AM
I have not actually copied straight to the layout object - I've cloned into the NOD then applied the particular plotsettings to the layout in question to plot.

Unfortunately I'm out of the country at the moment and won't be back until the 19th. If you're still having troubles, give me a shout then and I will post up something.

Until then, this is the order I would try:

open up source dwg in memory
start transaction on it
get the object in question
start transaction on destination db/object
open up destination object
copy/clone it across
end transaction on destination db
end transaction on source db

Cheers,
Glenn.

PS and Kerry is right, it's a bit of black magic, smoke and mirrors where plotting is concerned.
Title: Re: Copying plot settings
Post by: Bobby C. Jones on January 05, 2007, 08:59:31 AM
Not related to your question, but don't forget to .Dispose() of any databases that you create.

Code: [Select]
Database controlDb = new Database();
...Insert Black Magic Here
controlDb.Dispose();

You'll want to wrap that in a using(Database controlDb = new Database()) or a Try..Catch..Finally statement.
Title: Re: Copying plot settings
Post by: Kerry on January 05, 2007, 09:44:36 AM
Would someone like to give this a run around the yard please.
It should import ALL the page setups from the template drawing ..

Added Note : This is concept code. You should check each PageSetup to see if it exists in the current drawing  and act accordingly .. otherwise you may end up with multiple copies [ yes, really ;-) ]

Another Note : I don't think this code will be suitable for public consumption .. the WblockCloneObjects does not work the way I expected.
.. the DuplicateRecordCloning.Ignore, does not Ignore the existing record
and
.. the DuplicateRecordCloning.Replace, spits the dummy in a rather rude manner.

I'll leave the code in case anyone gets any ideas.
... back to the drawing board  :-(

Code: [Select]
// Codehimbelonga kwb@theSwamp  Kerry Brown 20070105
// Credits to Glenn R for original concept.
// For AC2007: VS2005

        [CommandMethod("PSI")]
        static public void PageSetupsImport()
        { 
            Document doc = AcadApp.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
           
            ObjectIdCollection psIds = new ObjectIdCollection();

            using (Database psDb = new Database(false, true))
            {
                psDb.ReadDwgFile(@"c:\Scripter.dwg", System.IO.FileShare.ReadWrite, true, string.Empty);
                using (Transaction psTr = psDb.TransactionManager.StartTransaction())
                {
                    DBDictionary psDicts =  (DBDictionary)psTr.GetObject(
                        psDb.PlotSettingsDictionaryId, OpenMode.ForRead);

                    foreach (System.Collections.DictionaryEntry psDict in psDicts)
                    {
                        psIds.Add((ObjectId)psDict.Value);
                    }
                }
                IdMapping idMap = new IdMapping();
                db.WblockCloneObjects(
                    psIds,
                    db.PlotSettingsDictionaryId,
                    idMap,
                    DuplicateRecordCloning.Ignore,
                    false);
            }
        }

Title: Re: Copying plot settings
Post by: It's Alive! on January 05, 2007, 12:17:18 PM
Wow! Kerry
Very creative

Dan
Title: Re: Copying plot settings
Post by: mohnston on January 05, 2007, 01:01:49 PM
Thank you all for your interest, work, comments, guesses and input.
I continue to try to get to the bottom of this.

If you want an idea of the end goal take a look at AutoCAD's Publish feature.
Note that you can select many drawings, import a Page Setup, and use that setup on all the drawings in your list.
I'm building a program that is like Publish but built to fill our company's needs.

As I understand it the players are:
The subjectDocument - a Document to print
The controlDB - a Database that contains many plot settings (called Page Setups in AutoCAD). My preset, approved, pristine plot settings
The pSet - a PlotSettings (a single PlotSettings object out of the PlotSettings collection) that I want
The pInfo - a PlotInfo which contains all the information that AutoCAD should need to plot a given page

The idea (suggested by some here) was to not have to set all the many settings needed to plot a drawings. Instead import a Page Setup (plotsettings) from a source database.

I think I need a transaction to get the pSet because I am pulling an object out of a database.
I don't think I need a transaction to print subjectDocument because I'm not changing anything about the drawing. I'm not adding or reading anything from that drawing file.
When a drawing is printed using the Publish feature the Page Setup used to print the drawing does not get added to the drawing file.
I think the PlotInfo is a separate set of parameters that can be applied to any drawing.

I shall persevere.

Title: Re: Copying plot settings
Post by: mohnston on January 05, 2007, 08:45:16 PM
Ever notice how sometimes explaining a problem helps you to answer it?

. . .
If you want an idea of the end goal take a look at AutoCAD's Publish feature.
. . .
I'm building a program that is like Publish but built to fill our company's needs.

Autodesk.AutoCAD.ApplicationServices.Application.Publisher
Title: Re: Copying plot settings
Post by: Kerry on January 05, 2007, 09:19:29 PM
Mark, I just came back to post that namespace link for you :-)

... yep, sometimes the question is the answer.
Title: Re: Copying plot settings
Post by: Glenn R on January 30, 2007, 07:40:19 PM
Daniel,

The reason you don't get an exception when the dwg is CLOSED is because of this line:
Code: [Select]
controlDB.ReadDwgFile(plotControlDWG, System.IO.FileShare.Read, false, string.Empty);

The FileShare.Read is telling it that you want to LOCK the file, read it and only allow read access to others...hence if you have it open, it's already locked and your code can't get an exclusive lock.

Kerry and others,

Are you still having trouble findinng an optimum solution for this? If yes, create a template file with some named pagesetups in it, then post back and we can have a little lesson/experiment.

I won't do this if there's little interest.

Cheers,
Glenn.
Title: Re: Copying plot settings
Post by: Kerry on January 30, 2007, 07:58:26 PM
Hi Glenn .. great to have you back from your holidays ... hope you had a fun time !!

I'd be interested in playing along ... just can't apply ongoing undivided attention at the moment
 be assured that your postings will be followed with interest, even if most viewers don't respond  :|

I had thought that CopyFrom would do the job, but haven't made the time to follow the idea through ..

/// kwb

Title: Re: Copying plot settings
Post by: Glenn R on January 30, 2007, 08:11:56 PM
Oooook then.

First a few experiments.

1. Put this code into the ThisDrawing module in a new VBA project and change the variable 'sTemplate' to point to your template.
2. Make sure to add a reference in VBA to AutoCAD/ObjectDBX Common 16.0 Type Library as well.
Code: [Select]
Public Sub ImportPageSetupsToCurrentDwg()
    Dim pAxDbDoc As AxDbDocument
    Dim pAxDbPageSetups As AcadPlotConfigurations
    Dim pAxDbPageSetup As AcadPlotConfiguration
    Dim pltCfgsArray() As AcadPlotConfiguration
    Dim i As Integer
    Dim sTemplate As String
   
    On Error Resume Next
    If Err Then Err.Clear
   
    Set pAxDbDoc = New AxDbDocument
    sTemplate = "C:\Temp\Plot.dwt"
    pAxDbDoc.Open sTemplate
   
    If Err Then
        Err.Clear
        MsgBox Err.Description
        MsgBox "Error opening " & sTemplate & "!", vbExclamation, "Batch Error"
        Set pAxDbDoc = Nothing
        Exit Sub
    End If
   
    ' get a pointer to the pagesetups in the in-memory dbase...
    Set pAxDbPageSetups = pAxDbDoc.PlotConfigurations
    ' loop the pagesetup's and add them...
    i = -1
    For Each pAxDbPageSetup In pAxDbPageSetups
        i = i + 1
        ReDim Preserve pltCfgsArray(i) As AcadPlotConfiguration
        Set pltCfgsArray(i) = pAxDbPageSetup
    Next
    ' clone the plot configs (pagesetups) into the current dwg...
    pAxDbDoc.CopyObjects pltCfgsArray, ThisDrawing.PlotConfigurations
    ' check if the clone op worked...
    If Err Then
        Err.Clear
    End If
   
    ' Clean up...
    For i = LBound(pltCfgsArray) To UBound(pltCfgsArray)
        Set pltCfgsArray(i) = Nothing
    Next
    Set pAxDbPageSetup = Nothing
    Set pAxDbPageSetups = Nothing
    Set pAxDbDoc = Nothing
   
    If Err Then Err.Clear
End Sub

Now, run the code, then right click on a layout tab and go to the Page Setup Manager, and you should see all the pagesetups from your template have been imported.

Now, just for kicks, run the code again and revisit the Page Setup Manager...what do you see? Report your findings here.

Cheers,
Glenn.
Title: Re: Copying plot settings
Post by: Glenn R on January 30, 2007, 08:14:04 PM
BTW, I'm using 2006 and Visual Studio 2005.
Title: Re: Copying plot settings
Post by: Kerry on January 30, 2007, 08:34:23 PM
Now, run the code, then right click on a layout tab and go to the Page Setup Manager, and you should see all the pagesetups from your template have been imported.

Now, just for kicks, run the code again and revisit the Page Setup Manager...what do you see? Report your findings here.

First Pass .. the Page setups were imported and Listed.
Second Pass .. each Page setups is listed twice
Title: Re: Copying plot settings
Post by: Glenn R on January 30, 2007, 09:07:23 PM
Excellent Kerry.

Can you guesstimate as to why they're duplicated? Also, have a look in the ACAD_PLOTSETTINGS dictionary in the NOD (Named Objects Dictionary) with DBVIEW...you will some interesting results.
Title: Re: Copying plot settings
Post by: Glenn R on January 30, 2007, 09:19:58 PM
Also, when you've fired up DBVIEW and looked where I suggested, post your findings and musings here.
Title: Re: Copying plot settings
Post by: Kerry on January 30, 2007, 09:38:41 PM
Heh, they're all anonymous !!
Title: Re: Copying plot settings
Post by: Glenn R on January 30, 2007, 09:48:45 PM
Excellent...why?
Title: Re: Copying plot settings
Post by: Glenn R on January 30, 2007, 09:50:19 PM
Also, click on one of the anon names (*A?), then in the right hand pane view, look at the 001 code...what do you notice?
Post your findings here.
Title: Re: Copying plot settings
Post by: Kerry on January 30, 2007, 09:54:11 PM
Excellent...why?

no sensible idea ..

Title: Re: Copying plot settings
Post by: Kerry on January 30, 2007, 09:59:46 PM
Also, click on one of the anon names (*A?), then in the right hand pane view, look at the 001 code...what do you notice?
Post your findings here.

I'd noticed the name .. was trying to find a relationship with ID's, but ..
Title: Re: Copying plot settings
Post by: Glenn R on January 30, 2007, 10:06:21 PM
It's because they're dictionary entries and they aren't hard owned by default. Groups don't survive a wblock do they...
I remember reading some little tidbit of info in the ARX docs to support this, hence, when code copies them over, it gives them anonymous 'keys' in the dictionary.

Here is one way of copying them over.Note that I probably could have responded to the endDeepClone event instead of this:
Code: [Select]
public static bool ImportPageSetups(Document doc) {

// Do we have our template dbase?
if (_batchPageSetupTemplate == null)
return false; // Nope - bail out immediately!

// Get a pointer to the current doc's dbase...
Database curDb = doc.Database;

// Declare 2 transaction objects - one for each dbase...
Transaction curDbTr = null;
Transaction psDbTr = null;

Transaction psRenameTr = null;

// Objectid collection to hold the pagesetups we're going to clone...
ObjectIdCollection psIds = new ObjectIdCollection();

IdMapping psIdMap = null;

using (DocumentLock docLock = doc.LockDocument()) {

// Using a try/finally construct here as it's neater than
// trying to nest multiple using statements.
try {
// Kick off the transaction on the template dbase...
psDbTr = _batchPageSetupTemplate.TransactionManager.StartTransaction();
// ...also, kick off a trtansaction on the current dbase as well...
curDbTr = curDb.TransactionManager.StartTransaction();

// Open up the PlotSettings Dictionary on both dbase's...
DBDictionary curDbPsDict = (DBDictionary)curDbTr.GetObject(curDb.PlotSettingsDictionaryId, OpenMode.ForRead);
DBDictionary psDbPsDict = (DBDictionary)psDbTr.GetObject(_batchPageSetupTemplate.PlotSettingsDictionaryId, OpenMode.ForRead);

// Loop over the plot settings dictionary in the template and
// try to get the same entry in the current drawing.
// If we DO get it, erase it...
foreach (System.Collections.DictionaryEntry psDbPs in psDbPsDict) {
// Get the name...
string psName = (string)psDbPs.Key;

// Does it exist in our current dbase?
if (curDbPsDict.Contains(psName)) {
// Get it...
ObjectId curDbPsId = curDbPsDict.GetAt(psName);
// open it up...
PlotSettings curDbPs = (PlotSettings)curDbTr.GetObject(curDbPsId, OpenMode.ForWrite);
// Erase it...
curDbPs.Erase();
// Add this page setup object id into our collection of objects to clone...
psIds.Add((ObjectId)psDbPs.Value);
} else
psIds.Add((ObjectId)psDbPs.Value);

}//foreach

// OK, we now should have our list of objectid's to clone, but to be
// safe we check...
if (psIds.Count == 0)
return false;

// Got id's, so clone 'em
psIdMap = curDb.WblockCloneObjects(psIds, curDb.PlotSettingsDictionaryId, DuplicateRecordCloning.Ignore, false);

// Commit the transaction on our current dbase - we can abort the
// one on the template as we're not doing anything...
curDbTr.Commit();


// We need to commit the last transaction, above, and start a new one,
// as I suspect the cloned objects id's are in flux inside the above transaction,
// and we can't reliably access them.

psRenameTr = curDb.TransactionManager.StartTransaction();

DBDictionary dbDict = (DBDictionary)psRenameTr.GetObject(curDb.PlotSettingsDictionaryId, OpenMode.ForWrite);

// OK, we have an idmap, so loop it...
foreach (IdPair psIdPair in psIdMap) {
ObjectId id = psIdPair.Value;
DBObject obj = psRenameTr.GetObject(id, OpenMode.ForRead);

PlotSettings newPs = obj as PlotSettings;
if (newPs == null)
continue;

// Upgrade open...
newPs.UpgradeOpen();

string anonymousName = dbDict.NameAt(id);
// Set the correct name...
dbDict.SetName(anonymousName, newPs.PlotSettingsName);
}

psRenameTr.Commit();

} finally {

if (curDbTr != null)
curDbTr.Dispose();

if (psDbTr != null)
psDbTr.Dispose();

if (psRenameTr != null)
psRenameTr.Dispose();

}
}

return true;
}

Hope this helps.

Cheers,
Glenn.
Title: Re: Copying plot settings
Post by: Kerry on January 30, 2007, 10:12:06 PM
.... and they aren't hard owned by default. ...

I'll need to stop and think about this later, but OK :-)

Title: Re: Copying plot settings
Post by: Kerry on January 30, 2007, 10:15:02 PM
Here is one way of copying them over.Note that I probably could have responded to the endDeepClone event instead of this:
Code: [Select]
public static bool ImportPageSetups(Document doc) {
///.......................
}

Hope this helps.

Cheers,
Glenn.

I'll print this out and have a good look tonight Glenn

Thanks Mr. !!
Title: Re: Copying plot settings
Post by: Glenn R on January 30, 2007, 10:23:20 PM
Note that this was being used in a batch scenario, hence the Document argument to the function and also the document locking, as it was called from the Application execution context.
Title: Re: Copying plot settings
Post by: Kerry on January 30, 2007, 10:33:13 PM
Note that this was being used in a batch scenario, hence the Document argument to the function and also the document locking, as it was called from the Application execution context.

Yep, I noticed the Template Database _batchPageSetupTemplate was a class variable ( or property)
Title: Re: Copying plot settings
Post by: Kerry on January 30, 2007, 11:22:40 PM
...

Here is one way of copying them over.....

That's a fairly intricate solution Glenn ... must have taken a couple of concept jumps to get there ..

Title: Re: Copying plot settings
Post by: Kerry on January 30, 2007, 11:28:06 PM
Looks like I was sortof on the right track ..  :|
http://www.theswamp.org/index.php?topic=14290.msg172196#msg172196
Title: Re: Copying plot settings
Post by: Glenn R on January 30, 2007, 11:41:59 PM
Quote
That's a fairly intricate solution...

Not really Kerry - it's essentially what I mentioned to try in pseudo form earlier in this thread, which you did. Kudos.
I wrote this quite a while ago and it probably could be cleaned up a bit.

The concept was what I had in mind from the start. I've known about the anon entries for a few years now, from when I implemented a VBA batching program. I got around the duplicates by blatantly erasing all the pagesetups in the target drawing during the batch run. This has the added bonus that you can change them in your template and be assured that every drawing batched will always have the latest page setup.

I still do this, however I now go through and 'fix' the anon names to what they should be.

Essentially, you read your template dbase, get the ids of all the pagesetups you're interested in, clone 'em, commit that transaction, then open the newly cloned pagesetups and fix up their names - not really that intricate...once you sort it out ;)

Somebody might come up with a revised version of this...

Hope it helps some Kerry.

Cheers,
Glenn.
Title: Re: Copying plot settings
Post by: Kerry on January 30, 2007, 11:49:39 PM
........  I got around the duplicates by blatantly erasing all the pagesetups in the target drawing during the batch run. This has the added bonus that you can change them in your template and be assured that every drawing batched will always have the latest page setup.
.........


Just been through this .. a new printer here at home, and some changes at 'work' mean that almost ALL the Pagesetups changed.

I used PSETUPIN in a script situation on ALL drawings [ I'll leave the quantum to your imagination]

I'll have a good look at your solution when my head clears ..

Thanks
/// kwb
Title: Re: Copying plot settings
Post by: Glenn R on January 30, 2007, 11:53:40 PM
You're welcome Kerry.
Once you have a page setup, or should I say, PlotSettings object, it makes  plotting a WHOLE lot easier as you just apply the page setup.
I'm interested to hear your comments.

Cheers,
Glenn.
Title: Re: Copying plot settings
Post by: Kerry on January 31, 2007, 12:05:10 AM
To me, importing from a template wins hands down over trying to set the properties in code .. one reason is that the config can be modified without the necessity of re-working/recompiling the solution .. and the methodology is transparent and auditable.

I'd still like to investigate the copyFrom() method just for my education .. but that won't be this week .. :-D
Title: Re: Copying plot settings
Post by: Glenn R on January 31, 2007, 12:11:22 AM
Can you elaborate there Kerry - I might have a go at it and see what I come up with.
Title: Re: Copying plot settings
Post by: Kerry on January 31, 2007, 12:14:11 AM
Re DBview for AC2007 ...

can be found here .. http://autodesk.blogs.com/between_the_lines/2006/07/dbview_for_auto.html
Title: Re: Copying plot settings
Post by: Kerry on January 31, 2007, 12:26:20 AM
Can you elaborate there Kerry - I might have a go at it and see what I come up with.

I've seen a C++ solution to copy a Layout which uses copyFrom.
I don't know if it's translatable to managed code.

Because the Layout class derives from the Plotsettings class I thought we may be able to use the same methodology.

Just a W.A.G. I thought I'd investigate

 
Title: Re: Copying plot settings
Post by: Glenn R on January 31, 2007, 01:03:45 AM
Good call Kerry - run this up the flagpole and see who salutes it:

Code: [Select]
[CommandMethod("CopyPlotSettings", CommandFlags.NoTileMode)]
static public void CopyPlotSettings( )
{
Document doc = acadApp.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;

LayoutManager layoutMan = LayoutManager.Current;
ObjectId currentLayoutId = layoutMan.GetLayoutId(layoutMan.CurrentLayout);

using (Transaction tr = db.TransactionManager.StartTransaction())
{
Layout currentLayout = tr.GetObject(currentLayoutId, OpenMode.ForWrite, false) as Layout;
if (currentLayout == null)
return;

using (Database templateDb = new Database(false, true))
{
templateDb.ReadDwgFile(@"C:\Temp\Plot.dwt", System.IO.FileShare.ReadWrite, false, null);
using (Transaction dwtTr = templateDb.TransactionManager.StartTransaction())
{
DBDictionary plotsettingsDict = dwtTr.GetObject(templateDb.PlotSettingsDictionaryId, OpenMode.ForRead) as DBDictionary;
ObjectId plotsettingId = plotsettingsDict.GetAt("A1-A3 DWF");
PlotSettings pageSetup = dwtTr.GetObject(plotsettingId, OpenMode.ForRead) as PlotSettings;

// Copy it over as per Kerry's suggestion...
currentLayout.CopyFrom(pageSetup);
}
}

tr.Commit();
}

}

This is turning into an interesting thread.

Cheers,
Glenn.
Title: Re: Copying plot settings
Post by: Kerry on January 31, 2007, 01:17:22 AM
Good call Kerry - run this up the flagpole and see who salutes it:
..................
This is turning into an interesting thread.

Cheers,
Glenn.

That looks like a plan ... I'll have a play after dinner

... yes, this has turned into a fun thread .... and unusually it's almost stayed on topic.

Good stuff Glenn
Title: Re: Copying plot settings
Post by: Kerry on January 31, 2007, 01:27:42 AM
 :-) nice touch ..

Code: [Select]
CommandFlags.NoTileMode
Title: Re: Copying plot settings
Post by: Glenn R on January 31, 2007, 01:33:13 AM
Thankyou :D
Title: Re: Copying plot settings
Post by: T.Willey on January 31, 2007, 11:16:23 AM
Though I only read over everything you two have posted (Kerry and Glenn) I will look more indepth when my brain is ready.  Thank you both for sharing your knowledge, this does sound like fun.
Title: Re: Copying plot settings
Post by: Glenn R on January 31, 2007, 08:30:13 PM
Us lot have a weird defintion of fun eh. ;)

I just found that one sentence in the ARX docs which confirms the behaviour exhibited when cloning dictionary entries:

Quote
AcDbDatabase::wblockCloneObjects Function Acad::ErrorStatus

wblockCloneObjects(

AcDbObjectIdArray& objectIds,

AcDbObjectId& owner,

AcDbIdMapping& idMap,

AcDb::DuplicateRecordCloning drc,

bool deferXlation = false);

objectIds Input array of objects to be deep cloned
owner Input object ID of object to be the owner of the clones
idMap Returns array of AcDbIdPair objects to be used for translating object ID relationships
drc Input action for duplicate records
deferXlation Input Boolean indicating whether or not ID translation should be done

Clones all objects in the objectIds array and appends them to the container object specified by owner. The objects can be from multiple source databases, and must match the type of owner supplied, but must be from a different database than the owner object.

owner can only be an AcDbBlockTableRecord, AcDbDictionary, or AcDbSymbolTable object. In multiple calls, the owners must be from the same destination database. If the owner is a dictionary, newly cloned entries are set as anonymous.
...
...

Cheers,
Glenn.
Title: Re: Copying plot settings
Post by: Kerry on February 01, 2007, 10:30:27 PM
.............. I just found that one sentence in the ARX docs which confirms the behaviour

Sometimes, that's all it takes I 'spose ..
Title: Re: Copying plot settings
Post by: Glenn R on February 01, 2007, 11:00:37 PM
Hehehe...but it's finding it AGAIN when you know you've "seen it somewhere".

It seems like we're the only 2 interested in this Kerry. For the sake of completeness,
here is a cleaned up implementation that should be easier to follow:

Code: [Select]
[CommandMethod("IPS", CommandFlags.NoTileMode)]
static public void ImportPageSetupCommand( )
{
Database dwtDb = null;

// Get a pointer to the current doc's dbase...
Document doc = acadApp.DocumentManager.MdiActiveDocument;
Database db = doc.Database;

Transaction dwtDbTr = null;

// Objectid collection to hold the pagesetups we're going to clone...
ObjectIdCollection psIds = new ObjectIdCollection();
IdMapping psIdMap = null;

try
{
dwtDb = new Database(false, true);
dwtDb.ReadDwgFile(@"C:\Temp\Plot.dwt", System.IO.FileShare.ReadWrite, false, null);

// Kick off the transaction on the template dbase...
dwtDbTr = dwtDb.TransactionManager.StartTransaction();

DBDictionary dwtDbPsDict = dwtDbTr.GetObject(dwtDb.PlotSettingsDictionaryId, OpenMode.ForRead) as DBDictionary;

foreach (System.Collections.DictionaryEntry psDbPs in dwtDbPsDict)
psIds.Add((ObjectId)psDbPs.Value);

if (psIds.Count == 0)
return;

dwtDbTr.Commit();

// Got id's, so clone 'em
psIdMap = db.WblockCloneObjects(psIds, db.PlotSettingsDictionaryId, DuplicateRecordCloning.Ignore, false);

RenameAnonymousPageSetups(psIdMap);

}
finally
{
if (dwtDbTr != null)
dwtDbTr.Dispose();

if (dwtDb != null)
dwtDb.Dispose();

}

return;
}

static void RenameAnonymousPageSetups(IdMapping plotSettingsIdMap)
{
Database db = plotSettingsIdMap.DestinationDatabase;

using (Transaction tr = db.TransactionManager.StartTransaction())
{
DBDictionary psDict = tr.GetObject(db.PlotSettingsDictionaryId, OpenMode.ForWrite, false) as DBDictionary;
if (psDict == null)
return;

foreach (IdPair psIdPair in plotSettingsIdMap)
{
ObjectId id = psIdPair.Value;
PlotSettings ps = tr.GetObject(id, OpenMode.ForWrite, false) as PlotSettings;

if (ps == null)
continue;

if (psDict.Contains(ps.PlotSettingsName))
{
ObjectId existingPsId = psDict.GetAt(ps.PlotSettingsName);
if (existingPsId != ObjectId.Null)
psDict.Remove(existingPsId);
}

string anonymousName = psDict.NameAt(id);

psDict.SetName(anonymousName, ps.PlotSettingsName);

}

tr.Commit();
}
}

Cheers,
Glenn.
Title: Re: Copying plot settings
Post by: Kerry on February 01, 2007, 11:23:15 PM
That looks pretty Glenn .. I'll give it a run tomorrow.

I've given up worrying about who's demonstrating interest right now .. I count on 'someone' getting the confidence to post their own stuff down the road a little so we can all continue this learning process.
Title: Re: Copying plot settings
Post by: Glenn R on February 01, 2007, 11:43:28 PM
It's certainly prettier than the first, but essentially the same concept.

I'm fast giving up as well - the thing that annoys me no end...people who don't even say thankyou, or "I figured it out, here it is..."
I was going to continue this on in the plotting thread that was started and show how to do it with pagesetups...oh well...

Rant off (having a bad day)
Title: Re: Copying plot settings
Post by: Kerry on February 02, 2007, 02:07:26 AM
... I was going to continue this on in the plotting thread that was started and show how to do it with pagesetups...oh well...

..

go for it !!!
That thread deals with layouts too, so the same principle could be applied .. < perhaps>
... one thing I have found is that posting code or answers helps me to clarify <somewhat> my thinking, so I post for purely selfish reasons ... :-D
Title: Re: Copying plot settings
Post by: mohnston on February 02, 2007, 04:11:22 PM
I'm here for you.

Judging by the number of plotting questions and the lack of documentation or good answers I would say people are watching this thread. I know I am. And if they aren't watching it now they will certainly be reading it when they try to write a plotting program.

My current solution for batch plotting involves using Page Setups. The setups are stored in what I call a "control" drawing. I import them for plotting by using the Publish mechanism. I don't know if it copies the setup into the drawing or just uses the settings.

I ended up creating a DSD file (sDsdFile). Then I plot my files using "Application.Publisher.PublishDsd(sDsdFile, prog);" (prog is a PlotProgressDialog)
The format of the dsd file wasn't too difficult. One of the lines that is in every sheet description is in the format SetupName|PathToFileContainingSetup:
Setup=mySetupName|\\Full\path\to\my\control\drawing.dwg

Code: [Select]
        public void BatchPlot(ArrayList fullPathList, SourceOfPlot source, PaperSize paper, string DeviceName)
        {
            // Page Setup will be pulled from control dwg file plotControlDWG
            if (fullPathList.Count < 1) return;
            // Page Setup will be pulled from control dwg file plotControlDWG
           
            string pgSetupName = ""; // SOURCE + "-" + PAPER + "-" + DEVICE
            pgSetupName = BuildPageSetupName(source, paper, DeviceName);
            if (FileHasPageSetup(plotControlDWG, pgSetupName) == false)
            {
                // throw error here
                return;
            }
            string fullName = "";
            string shortName = "";
            StringBuilder sbDSD = new StringBuilder();
            // dsd file HEADER
            sbDSD.AppendLine("[DWF6Version]");
            sbDSD.AppendLine("Ver=1");
            sbDSD.AppendLine("[DWF6MinorVersion]");
            sbDSD.AppendLine("MinorVer=1");
            // dsd file LOOP
            for (int i = 0; i < fullPathList.Count; i++)
            {
                fullName = fullPathList[i].ToString();
                shortName = GetShortFileName(fullName);
                sbDSD.AppendLine("[DWF6Sheet:" + shortName.Substring(0, shortName.Length -4) + "]");
                sbDSD.AppendLine("DWG=" + fullName);
                sbDSD.AppendLine("Layout=Model");
                sbDSD.AppendLine("Setup=" + pgSetupName + "|" + plotControlDWG);
                sbDSD.AppendLine("OriginalSheetPath=" + fullName);
                sbDSD.AppendLine("Has Plot Port=0");
                sbDSD.AppendLine("Has3DDWF=0");
            }                       

            // dsd file CLOSER
            sbDSD.AppendLine("[Target]");
            sbDSD.AppendLine("Type=" + PubTypeString(MyPubType));
            if (File.Exists(MyDWFFile)) File.Delete(MyDWFFile);
            sbDSD.AppendLine("DWF=" + MyDWFFile);
            sbDSD.AppendLine("OUT=" + MyPLTPath);
            sbDSD.AppendLine("PWD=");
            sbDSD.AppendLine("[AutoCAD Block Data]");
            sbDSD.AppendLine("IncludeBlockInfo=0");
            sbDSD.AppendLine("BlockTmplFilePath=");
            sbDSD.AppendLine("[SheetSet Properties]");
            sbDSD.AppendLine("IsSheetSet=FALSE");
            sbDSD.AppendLine("IsHomogeneous=FALSE");
            sbDSD.AppendLine("SheetSet Name=");
            sbDSD.AppendLine("NoOfCopies=1");
            sbDSD.AppendLine("PlotStampOn=FALSE");
            sbDSD.AppendLine("JobID=0");
            sbDSD.AppendLine("SelectionSetName=");
            sbDSD.AppendLine("AcadProfile=<<VANILLA>>");
            sbDSD.AppendLine("CategoryName=");
            sbDSD.AppendLine("LogFilePath=");
            sbDSD.AppendLine("IncludeLayer=FALSE");
            sbDSD.AppendLine("PromptForDwfName=TRUE");
            sbDSD.AppendLine("PwdProtectPublishedDWF=FALSE");
            sbDSD.AppendLine("PromptForPwd=FALSE");
            sbDSD.AppendLine("RepublishingMarkups=FALSE");
            sbDSD.AppendLine("PublishSheetSetMetadata=FALSE");
            sbDSD.AppendLine("PublishSheetMetadata=FALSE");
            sbDSD.AppendLine("3DDWFOptions=0 0");
           
            string sDsdFile = @"C:\dsdfile.dsd";
            File.Delete(sDsdFile);
            File.WriteAllText(sDsdFile,sbDSD.ToString());
           
            PlotProgressDialog prog = new PlotProgressDialog(false, fullPathList.Count , true);
            try
            {
                if (Application.DocumentManager.Count == 1)
                {
                    if (Application.DocumentManager.MdiActiveDocument.Name.ToUpper().Contains("DRAWING"))
                    {
                        Application.DocumentManager.Add(blankTemplateFile);
                    }
                }
                if (Application.DocumentManager.Count < 1)
                {
                    Application.DocumentManager.Add(blankTemplateFile);
                    Application.DocumentManager.Add(blankTemplateFile);
                }

                string backGround = Application.GetSystemVariable("BackgroundPlot").ToString();
                Application.SetSystemVariable("BackgroundPlot", 0);
               
                Application.Publisher.PublishDsd(sDsdFile, prog);
               
                Application.SetSystemVariable("BackgroundPlot", Convert.ToInt32(backGround));
            }
            catch (System.Exception ex)
            {
                System.Windows.Forms.MessageBox.Show("An error occured in the BatchPlot function of cMyPlot class.\n" +
                    ex.Message + "\nReport this error to Mark", "Batch plot error");
                // throw;
            }
            finally
            {
                prog.Destroy();
                prog.Dispose();
            }
        }

I am still working out a few issues. I may end going with what you posted.
Title: Re: Copying plot settings
Post by: Chuck Gabriel on February 02, 2007, 06:29:05 PM
lack_of_posting != lack_of_interest

My interest is, however, somewhat limited by the fact that AutoCAD 2000i doesn't have a .NET API.  :D

I still like to keep up, though, due to natural curiosity and the possibility that I may not be working in the same place forever.
Title: Re: Copying plot settings
Post by: Glenn R on February 02, 2007, 10:18:14 PM
This is pretty much a direct translation from the ARX docs - "Using the Plot API"
Title: Re: Copying plot settings
Post by: Kerry on February 02, 2007, 10:50:20 PM
Just running past ...
Thanks Glenn ... sometimes wish my old brain could handle the C++ translation to C# more easily.
I'm assuming you are feeding that from a previously saved file list ??



Mark,
I'd be interested in seeing your solution for writing/appending to the DSD file when you get your issues sorted out. I think this methodology may have some potential for something I have had fermenting for a while.
Title: Re: Copying plot settings
Post by: Glenn R on February 02, 2007, 10:59:04 PM
Kerry,

A Listview with all the drawings you want batched and a ListBox containing pagesetups...you can run mutiple plots to different devices/files all in one hit.
Title: Re: Copying plot settings
Post by: c_witt on June 19, 2013, 04:42:18 PM
Greetings from the future.

Just wanted to offer my thanks to all in this thread.   Solved my current problem.

Thank you.