VPClip using C#

VPClip using C#

amitnkukanur
Collaborator Collaborator
3,973 Views
14 Replies
Message 1 of 15

VPClip using C#

amitnkukanur
Collaborator
Collaborator

Hi,

 

Please suggest me what are the possibilities of doing a VPClip from C#, as i would like to achieve this function for a reason from .NET.

Not able to find any reference material to do this.

 

Any assistance will be appreciated.

 

 

Rgds,

Amit

Senior Software Engineer
0 Likes
Accepted solutions (1)
3,974 Views
14 Replies
Replies (14)
Message 2 of 15

norman.yuan
Mentor
Mentor

I assume you want to write code to do the same thing as AutoCAD built-in command "VPCLIP", using .NET API (C# or VB.NET does not matter here), right?

 

It is rather simple, if you loot at the Viewport class in .NET API document/VisualStudio's Object Browser:

 

Viewport class has a couple of read/write properties: "NonRectClipEntityId" (ObjectId of a Polyline) and "NonRectClipOn" (boolean).

 

So, here are what you do:

 

1. Find the target Viewport's Id (you can ask user to pick, loop through entities in paperspace, ...)

2. Find an existing polyline (closed, of course) in the same space as the viewport. You can ask user to pick. Or you have a set of points that can be turned into a polyline. 

3. Once you have both target viewport ID and an existing polyline Id (or a set of point that you can create a polyline by code), you start a transaction, open the viewport object, set its "NonRectClipEntityId" to the polyline's Id, and then set "NonrectClicpOn" to true. Commit the transaction. You are done.

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 3 of 15

amitnkukanur
Collaborator
Collaborator

Hi Norman,

 

Thanks for reply, i am thankful to you.

As you mentioned, what autocad is doing i would like to do the same thing with slight difference. When we do vpclip, it automatically erases the other portion of clip. I need need to maintain that as well. 

 

Do vpclip and keep the clipped portion there itself

 

 

I will try the approach which you mentioned, will keep you posted about the status.

 

 

Regards,

Amit

 

 

 

Senior Software Engineer
0 Likes
Message 4 of 15

amitnkukanur
Collaborator
Collaborator

Hi,

 

Below is the part of code which i borrowed from discussion forum only and made some minor changes to suit as you suggested, please suggest if am right or where all corrections to be made

 

Document curDoc = Application.DocumentManager.MdiActiveDocument;
            Database db = curDoc.Database;
            Editor ed = curDoc.Editor;
            ed.SwitchToPaperSpace();
            PromptEntityOptions eo = new PromptEntityOptions("\nSelect a viewport: ");
            eo.AllowNone = false;
            eo.SetRejectMessage("\nNeed to select a viewport!");
            eo.AddAllowedClass(typeof(Viewport), true);
            eo.AddAllowedClass(typeof(Polyline), true);
            eo.AddAllowedClass(typeof(Polyline2d), true);
            eo.AddAllowedClass(typeof(Polyline3d), true);
            eo.AddAllowedClass(typeof(Spline), true);
            PromptEntityResult er = ed.GetEntity(eo);
            if (er.Status != PromptStatus.OK)
                return;

            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                BlockTableRecord btr = (BlockTableRecord)trans.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                PromptEntityOptions peo = new PromptEntityOptions("\nSelect polyline");
                peo.SetRejectMessage("\nPlease select polyline");
                peo.AddAllowedClass(typeof(Viewport), false);
                peo.AddAllowedClass(typeof(Polyline), true);
                peo.AddAllowedClass(typeof(Polyline2d), true);
                peo.AddAllowedClass(typeof(Polyline3d), true);
                peo.AddAllowedClass(typeof(Spline), true);
                PromptEntityResult res;
                res = ed.GetEntity(peo);
                if (res.Status != PromptStatus.OK)
                    return;
                Entity ent = (Entity)trans.GetObject(res.ObjectId, OpenMode.ForWrite);
                if (ent == null)
                    return;
                Polyline poly1 = (Polyline)ent as Polyline;
                Entity newEnt = null;
                Viewport vpEnt = null;
                Entity selEnt = (Entity)er.ObjectId.GetObject(OpenMode.ForWrite);
                ObjectId vpId = LayoutManager.Current.GetNonRectangularViewportIdFromClipId(selEnt.Id);
                if (vpId == ObjectId.Null)
                    vpEnt = null;
                else
                {
                    vpEnt = (Viewport)vpId.GetObject(OpenMode.ForWrite);
                    newEnt = (Entity)selEnt.Clone();
                }
                Viewport vpp = new Viewport();
                 
                Extents3d vpExt = vpEnt.GeometricExtents;
                Polyline poly = new Polyline(4);
                poly.AddVertexAt(0, new Point2d(poly1.GetPoint2dAt(0).X, poly1.GetPoint2dAt(0).Y), 0, -1, -1);
                poly.AddVertexAt(1, new Point2d(poly1.GetPoint2dAt(1).X, poly1.GetPoint2dAt(1).Y), 0, -1, -1);
                poly.AddVertexAt(2, new Point2d(poly1.GetPoint2dAt(2).X, poly1.GetPoint2dAt(2).Y), 0, -1, -1);
                poly.AddVertexAt(3, new Point2d(poly1.GetPoint2dAt(3).X, poly1.GetPoint2dAt(3).Y), 0, -1, -1);
                poly.Closed = true;
                newEnt = poly;
                ed.SwitchToPaperSpace();
                BlockTable bt = (BlockTable)db.BlockTableId.GetObject(OpenMode.ForWrite);
                BlockTableRecord ms = (BlockTableRecord)bt[BlockTableRecord.PaperSpace].GetObject(OpenMode.ForWrite);
                ObjectId id = ms.AppendEntity(newEnt);
                trans.AddNewlyCreatedDBObject(newEnt, true);
                Viewport vp = new Viewport();
                ms.AppendEntity(vp);
                ObjectId targerVPId = vp.Id;
                //Find the existing polyline in the same space as viewport
                Polyline mypolyline = poly;

                trans.AddNewlyCreatedDBObject(vp, true);
                vp.NonRectClipEntityId = poly1.Id; //
                vp.NonRectClipOn = true;                
                ed.SwitchToPaperSpace();
                //try
                //{
                //    vp.On = true;
                //}
                //catch (System.Exception ex)
                //{
                //    System.Windows.Forms.MessageBox.Show(ex.ToString());
                //} 
                trans.Commit();
            }

 

As you suggested i am doing, but its not clipping the selected part of closed polygon/polyline/viewport.

 

Please suggest.

 

Rgds,

Amit

Senior Software Engineer
0 Likes
Message 5 of 15

norman.yuan
Mentor
Mentor

As I said in previous reply, it is quite simple to clip a viewport with an polyline: simply assign the polyline's Id to the viewport. 

 

I suppose you rushed you code so that there are quite a few lines that do not make sense (thus not worked as you expected): although the code asked user to pick a viewport and a polyline, your code somehow created 2 new Viewport objects and only one is added to the database. However, the viewport is added into wrong space - ModelSpace, and then the code is apply the clipping polyline to the not-see-able viewport.

 

So, the problem with your code is not how to clip a viewport, rather, it is getting a target viewport and clipping polyline PROPERLY/AS EXPECTED.

 

Anyway, here is some simple code to clip a viewport:

 

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using System;
using CadApp = Autodesk.AutoCAD.ApplicationServices.Application;

[assembly: CommandClass(typeof(SetNoRectViewport.MyCommands))]

namespace SetNoRectViewport
{
    public class MyCommands
    {
        [CommandMethod("ClipVp", CommandFlags.NoTileMode)]
        public static void RunDocCommand()
        {
            var dwg = CadApp.DocumentManager.MdiActiveDocument;
            var ed = dwg.Editor;

            try
            {
                ClipViewport(dwg);
            }
            catch(System.Exception ex)
            {
                ed.WriteMessage("\nError: {0}", ex.Message);
                ed.WriteMessage("\n*Cancel*");
            }
            finally
            {
                Autodesk.AutoCAD.Internal.Utils.PostCommandPrompt();
            }
        }

        private static void ClipViewport(Document dwg)
        {
            Editor ed = dwg.Editor;

            ed.SwitchToPaperSpace();

            //Select a Viewport
            var vpId = SelectEntity(
                ed, 
                typeof(Viewport), 
                "\nSelect a viewport:");
            if (vpId.IsNull)
            {
                ed.WriteMessage("\n*Cancel*");
                return;
            }

            HighlightEntity(vpId, true);

            //Select a polyline in the same layout
            var polyId = SelectEntity(
                ed, 
                typeof(Polyline), 
                "\nSelect a polyline in the same layout as the selected viewport:");
            if (polyId.IsNull)
            {
                HighlightEntity(vpId, false);
                ed.WriteMessage("\n*Cancel*");
                return;
            }

            HighlightEntity(vpId, false);

            ClipViewport(vpId, polyId);   
        }

        private static ObjectId SelectEntity(Editor ed, Type entityType, string msg)
        {
            var opt = new PromptEntityOptions(msg);
            opt.SetRejectMessage("\nInvalid selection: not a " + entityType.Name);
            opt.AddAllowedClass(entityType, true);

            var res = ed.GetEntity(opt);
            if (res.Status == PromptStatus.OK)
                return res.ObjectId;
            else
                return ObjectId.Null;
        }

        private static void ClipViewport(ObjectId vpId, ObjectId polyId)
        {
            using (var tran = vpId.Database.TransactionManager.StartTransaction())
            {
                var vport = (Viewport)tran.GetObject(vpId, OpenMode.ForWrite);
                vport.NonRectClipEntityId = polyId;
                vport.NonRectClipOn = true;
                tran.Commit();
            }
        }

        private static void HighlightEntity(ObjectId entId, bool highlight)
        {
            using (var tran = entId.Database.TransactionManager.StartTransaction())
            {
                var ent = (Entity)tran.GetObject(entId, OpenMode.ForRead);
                if (highlight)
                    ent.Highlight();
                else
                    ent.Unhighlight();

                tran.Commit();
            }
        }
    }
}

See this video clip showing the code in action:

 

http://autode.sk/2q81NIp

 

HTH

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 6 of 15

amitnkukanur
Collaborator
Collaborator

Hi Norman,

 

Thanks for reply.

 

I went through the code, one change am trying to do is when we clip, it actually erases the portion other than clipped one rather than Clip and maintain a copy

 

I am looking to clip and maintain as seperate entity and not to erase the clipped part.

 

Rgds,

Amit

Senior Software Engineer
0 Likes
Message 7 of 15

norman.yuan
Mentor
Mentor

The code I showed basically works in the same way as command VPCLIP. If that is not what you expected, sorry, I am afraid that I do not understand what exactly you want to do.

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 8 of 15

amitnkukanur
Collaborator
Collaborator

Hi Norman,

 

No doubt the code you provided works similar to autocad VPClip, but if they both work same way then there is no need for me to customize.

 

The difference am trying to make is when the part of drawing is clipped using VPClip, the remaining part vanishes and only the part which we need remains, this is what i am trying to get hold of.

 

I am trying to build a logic similar to vpclip provided it should not erase any part.

The video link which you shared clips and erases other part.

 

 

Regards,

Amit

 

Senior Software Engineer
0 Likes
Message 9 of 15

amitnkukanur
Collaborator
Collaborator
Technically what am trying to do is split a viewport.
VPClip and the code you provided does it, but erases the other part.

what am doing is split a viewport into two there by maintaining both parts.
Senior Software Engineer
0 Likes
Message 10 of 15

norman.yuan
Mentor
Mentor

Sorry, I am afraid that I still do not get what you really need to do. Obviously, VPCLIP command has nothing to do with splitting viewport. By splitting, it probably means change the existing viewport and creating new viewports.Maybe, what you want is to change/remove existing viewports, and/or add new viewports, then apply non-rectangle clips to the viewports. If your goal can be achieved manually, it would also be possibly achieved by code. Unfortunately I simply do not know what is it to do.

 

If you can post some pictures to show the "Before" and "After" the viewport or viewports look like, it may help others to understand your goal.

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 11 of 15

fieldguy
Advisor
Advisor

PMFJI - it sounds like you want to make a copy of the object before the clip?  If that's the case, what are you planning to do with the "new" object?  Put it on a no-plot layer or something?

 

This would involve checking the object class, and creating a new object of the same class - maybe not so easy.   

0 Likes
Message 12 of 15

amitnkukanur
Collaborator
Collaborator

Going on vacation for 3 days, will be back on tuesday. I will explain what am trying to achieve in tuesday's reply.

 

With Regards,

Amit

Senior Software Engineer
0 Likes
Message 13 of 15

amitnkukanur
Collaborator
Collaborator

Hi norman,

 

I have attached sample snapshots.

 

Snapshot 1 is my base viewport which has a polyline in it.

 

Snapshot 2 is my vpclipping process where i have selected the viewport and clipping process.

 

Snapshot 3 shows my final output, here in this snapshot as you can see there is difference between snapshot 1 and 3 the original data is clipped 

and the clipped part remains.

 

I am trying to get that details as well, the one which was erased and only clipped version remains.

 

Regards,

Amit

Senior Software Engineer
0 Likes
Message 14 of 15

amitnkukanur
Collaborator
Collaborator
Hi FieldGuy,

Am trying the same approach as you posted

1) I will copy the viewport
2) Clip the existing viewport
3) Paste the copied view port

what will happen here is i am interested in the clipped part and before clipped part in same drawing.

Regards,
Amit
Senior Software Engineer
0 Likes
Message 15 of 15

norman.yuan
Mentor
Mentor
Accepted solution

Seeing your pictures, I felt a bit more confused: it seems just as simple as creating a non-rectangle viewport, but why you made it sound so differently. Let me try to say what I saw from the pictures what you want to do:

 

1. in the first picture, it is a layout (paperspace) with a regular viewport, set to "PS" state. That is, through the viewport a polygon in the modelspace can be seen, but not touchable (until the viewport is turned to "MS" state). Here the entity seen in modelspace, be it a polyline or anything else, has nothing to do with what you are to do with viewport.

 

2. In picture 2, you draw a closed polyline on the layout, which is to be used to clip the only viewport on the layout.

 

3. in picture 3, you probably issued command VPCLICP, in the execution of the command, you pick the viewport first, then you picked the closed polyline you just drew. when the command is done, the viewport is gone (hidden, not erase, not changed), the polyline is used to show as non-rectangle viewport. and finally, the viewport is in "MS" state (thus, you can touch the entity inModelSpace through the viewport.

 

See the video below for the process.

 

So, the code I posted previously is perfectly apply to this case, and it is basically the same as the built-in command "VPCLIP. Thus, I am more confused as to what you really want.

 

Seeing you said "I am trying to get that details as well, the one which was erased and only clipped version remains.", I'd like remind you: the viewport is NOT ERASED. It is hidden. After clipping, if you select the non-rectangle viewport, in the properties window, you could see actually 2 entities are selected: a viewport and a polyline. that is because the polyline is now associated to the viewport as clipping border.

 

Sorry, I had hard time to understand you, probably not able to offer any more idea/help.

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes