Jump to content
Developer Wiki and Function Reference Links ×

Outside memory limits.


Assembly

Recommended Posts

I keep crashing in a PIO that uses

FUNCTION Create3Dobj(h: HANDLE; z, dZ: REAL): HANDLE;

BEGIN

IF h <> NIL THEN BEGIN

BeginXtrd(z, dZ);

MoveTo(0,0);

LineTo(1, 1);

EndXtrd;

Create3Dobj:=lnewobj;

DelObject(FIn3D(GetParent(CreateDuplicateObject(h, LNewObj))));

END;

END;

a number of times.... I have got this through on a couple runs, with a memory out of limits warning.

Any thing I can do to force more memory allocation?.

Link to comment

there is no problem with the function.

the function is called multiple times in the script.

It fails on the 4-5th execution.

The script draws a stud wall.

It preformed when used in a pallet.

When copied into a PIO point tool the failures started.

I have used this function in far more complex Menu tools. Is memory assigned differently for PIO's?.

Following your suggestion I did simplify down to use

htemp:=CreateDuplicateObject(h, LNewObj);

{ DelObject(FIn3D(GetParent(CreateDuplicateObject(h, LNewObj))));}

but still failing.

Link to comment

Also, have you tried stepping through the script with the debugger? (Do you need advice on how to do this?)

VS's error messages aren't very sophisticated. In addition it's a program running with an application, so if the script causes an issue with Vectorworks' memory allocation, it can be really hard to debug.

When VW has memory issues with a script, 99% of the time the issue is with trying to use a variable that is somehow invalid. In my experience, this is either from a real that has been assigned a number divided by 0 or an invalid handle.

My suspicion is with your nested, copied, and duplicated handles, you at some point are acting on a handle to an object that doesn't exist.

I think you need to provide us with a larger piece of the script. What is the container handle you pass to the function? Why are you using CreateDuplicateObject instead of just drawing the extrude inside the container?

-Josh

Link to comment

Yes I have followed the debugger extensively. This is how I know that it does execute the function above a number of times, and how I know that it is this function that kills VW after a few loops.

I have pastebined the code below. I use an $include into a menu command and a point object. The menu command executes perfectly. The point object hangs up. I don't get why?.

Why use hExturde.?.

If you can follow the script you will see that I only need to call:

hTemp:=D3_StudArray(D2_Framing(pFrameDepth,45),pWallLength,pWallHeight,600,0);

I can change the D2_Framing(x,x) to any any function that draws a 2D profile and returns a handle. That could be a steel profile or a composite Timber I beam profile. Some times the profile function returns the VAR value of the spacing that then gets passed back into the D3 function. This method has allowed for very fast 3D object script development.

A link to a paste bin page with code.

Pastebin

Link to comment
  • 2 weeks later...

OK, I took a look at your code and posted an update. In general, you lose a lot of sub-functions and reuse the same variable names as both local and global variables, so troubleshooting the code becomes more complex. I found some of the functions completely unnecessary (they were only called once), and some of your passed handles unnecessary, especially with more judicious use of LNewObj.

I think you may be using procedures and functions as a substitute for good commenting and descriptive variable names.

The biggest change is using D2_Framing directly in the extrude group and eliminating the framing profile that gets created as part of D3_StudArray. I couldn't exactly trace what was going on, but I think part of the issue is that a PIO is hybrid, so it can have 2D an 3D geometry. I think copying the 2D part of the PIO into the 3D part may have caused some issues.

A couple of other things:

RotateZ used hTemp instead of H. You check if h is NIL, but if HTemp is nil, that may have caused you issues.

You should check that the pitch is not equal to 90 or −90, or you will have a divide by 0.

You should check to see if the final stud of the loop will be placed partly on top of the end stud.

Using my mods, you can easily make stud width, pitch, and spacing parameters of the PIO.

PROCEDURE Template;

VAR

xAngleR,yAngelR,zAngleR,offsetX, offsetY, offsetZ: Real;

{ClassString:String;}

{hProfile :HANDLE;}

dummyH :HANDLE;

i: INTEGER;

iCount :INTEGER;

gStudWidth :REAL;

StudLength :REAL;

StudPoint :REAL;

Framewidth :REAL;

FrameHeight :REAL;

Spacing :REAL;

Pitch :REAL;

{x1,y1,x2,y2:REAL;}

tagstring:STRING;

FUNCTION AdjustforAngle(adjust:REAL;TheAngle:real):real;

BEGIN;

AdjustforAngle:=adjust*Tan(Deg2Rad(TheAngle));

END;

FUNCTION AdjustforAngleHypot(adjust:REAL;TheAngle:real):real;

BEGIN;

AdjustforAngleHypot:=adjust/cos(Deg2Rad(TheAngle));

END;

FUNCTION AdjustforAngleOpposite(adjust:REAL;TheAngle:real):real;

BEGIN;

AdjustforAngleOpposite:=adjust*Cos(Deg2Rad(TheAngle));

END;

FUNCTION AdjustforAngleAdjacent(adjust:REAL;TheAngle:real):real;

BEGIN;

AdjustforAngleAdjacent:=adjust*Sin(Deg2Rad(TheAngle));

END;

PROCEDURE RotateX(hTemp:Handle;rTemp:Integer);

Begin;

Set3DRot(hTemp,rTemp,0,0,0,0,0);

End;

PROCEDURE RotateY(hTemp:Handle;rTemp:Integer);

Begin;

Set3DRot(hTemp,0,rTemp,0,0,0,0);

End;

PROCEDURE RotateZ(h:Handle;rTemp:Integer);

BEGIN;

IF h<>NIL THEN

Begin

Set3DRot(h,0,0,rTemp,0,0,0);

End

ELSE Message('Nil Handle in RotateZ');

END;

PROCEDURE MoveObjX(hTemp:Handle;rTemp:Integer);

Begin;

Move3DObj(hTemp,rTemp,0,0);

End;

PROCEDURE MoveObjY(hTemp:Handle;rTemp:Integer);

Begin;

Move3DObj(hTemp,0,rTemp,0);

End;

PROCEDURE MoveObjZ(hTemp:Handle;rTemp:Integer);

Begin;

Move3DObj(hTemp,0,0,rTemp);

End;

PROCEDURE MoveObj_Length(hTemp:Handle);

VAR

x1,y1,x2,y2:REAL;

BEGIN

GetBBox(hTemp,x1,y1,x2,y2);

MoveObjX(hTemp,-x1);

END;

FUNCTION HDuplicate3D(h:HANDLE;x:REAL;y:REal;z:REAL):Handle;

BEGIN;

HDuplicate3D:=HDuplicate(h,0,0);

Move3DObj(HDuplicate3D,x,y,z);

END;

PROCEDURE D2_Framing(Framewidth:Real;Framedepth:Real);

BEGIN;

rrect(0,0,Framewidth,Framedepth,4,4);

END;

FUNCTION hXtrude(dZ:REAL):HANDLE;

BEGIN;

BeginXtrd(0, dZ);

D2_Framing(pFrameDepth, gStudWidth);

EndXtrd;

hXtrude:=LNewObj;

END;

PROCEDURE D3_Plate(FrameLength:Real;Pitch:Real;z:Real);

VAR

hTemp: HANDLE;

BEGIN;

hTemp:=hXtrude(AdjustforAngleHypot(FrameLength,Pitch));

RotateZ(hTemp,90);

RotateY(hTemp,90);

MoveObjZ(hTemp,z);

END;

PROCEDURE D3_Stud(FrameLength:Real;Pitch:Real;z:Real);

VAR

hTemp: HANDLE;

BEGIN;

TagString:='Stud';

hTemp:=hXtrude(AdjustforAngleHypot(FrameLength,Pitch));

RotateZ(hTemp,90);

MoveObj_Length(hTemp);

MoveObjZ(HTEMP,Z);

END;

BEGIN;

PushAttrs;

GetView(xAngleR,yAngelR,zAngleR,offsetX, offsetY, offsetZ);

SetView(0,0,0,0,0,0);

{//// Set Variables ////}

gStudWidth:=45 mm;

Framewidth:=pWallLength;

FrameHeight:=pWallHeight;

Spacing:=600 mm;

Pitch:=0;

{//// Set Stud Dimensions ////}

{can y1 = gStudWidth?}

{

D2_Framing(pFrameDepth, gStudWidth);

hProfile:=LNewObj;

GetBBox(hProfile,x1,y1,x2,y2);

}

y1:=gStudWidth;

StudLength:=FrameHeight-(2*y1);

D3_Stud(StudLength,0,Y1);

dummyH:=HDuplicate3D(LNewObj,Framewidth-Y1,0,0);

{//// Draw Studs ////}

icount:=Trunc(Framewidth/Spacing);

For i:=1 to icount DO Begin

StudPoint:=Spacing*i;

StudLength:=StudLength-AdjustforAngleAdjacent(StudPoint,Pitch);

D3_Stud(StudLength,0,Y1);

MoveobjX(LNewObj,StudPoint);

END;

{//// Draw Plates ////}

D3_Plate(Framewidth,0,0);

D3_Plate(Framewidth,Pitch,FrameHeight-Y1);

SetView(xAngleR,yAngelR,zAngleR,offsetX, offsetY, offsetZ);

PopAttrs;

{DEBUG}

END;

RUN(Template);

Link to comment

Joshua, Thank you very much for your time to look at this... but changing the functions to procedure is not what I'm after here.

I have very good reason why I have structured the code this way.

The hXtrude as a function that you pass a profile to means all the code developed can be reused for any and every shape that exists. If I want to create a new Aluminium Window profile all I do is $include the long list of functions, then code up the drawing of the profile get a handle to it and I have my three d Shape. I have a parsing script that converts a list of drawn symbols into code. (BeginSym and EndSym are replaced with Function (Symname):Handle). Thus I can very quickly draw profiles, convert it into code and make a PIO.

The help I want is not for the code to be rearranged. Specifically I want to know why when the same source file is $included into a menu function it execute, but $included into a PIO VW crashes.

Link to comment

Assembly, does this out of memory only occur on inWall objects or also outside?

I also looked into the code and agree with Joshua: you play with fire with the variables, too many possible NIL handles un-dealt with. Never use globals in functions which you mean to recycle. Not even a genius can foresee what happens if something goes wrong.

I'd search for a wrong handle. Not necessarily a NIL handle. Simply a wrong one.

Anytime you use CreateDuplicateObject in inWall PIOs you need to counter check handles to obsession. That can cause you problems.

I also had a pio which every now and then when inWall AND not top-plan would enter a loop of duplication of the wall where it was inserted. A wrong handle, simple as that. Caused thousands of wall duplications in few seconds. Sloppy scripting highest level. LOL!

FUNCTION D3_Stud(hProfile: HANDLE; FrameLength: Real; Pitch: Real; z: Real): HANDLE; 
		BEGIN; 
			TagString := 'Stud'; 

			hTemp := hXtrude(hProfile, AdjustforAngleHypot(FrameLength, Pitch)); 
			RotateZ(hTemp, 90); 
			MoveObj_Length(hTemp); 
			MoveObjZ(HTEMP, Z); 
			D3_Stud := hTemp; 
		END; 

o

Edited by _c_
Link to comment
Specifically I want to know why when the same source file is $included into a menu function it execute, but $included into a PIO VW crashes.

If the above is true then it must have something to do with the different behaviours of VSM and VSO.

In past posts you were working with nested pio's.... parent PIO placing other PIO's. Is this code part of that project?

All of my run-ins with out of memory problems have involved loops running out of control. With nested VSO's it is possible to construct event loops, where the parent changes the child, and the child changing causes the parent to change, and on and on until all memory is eaten up.

Above is total guesswork and conjecture, but what I'm trying to suggest is that instead of thinking along the lines of forcing more memory or tweaking bits of code, the problem may be more in the implementation of the code: the differences between VSM and VSO.

The principal difference as I understand it is the constant event monitoring of VSO.

On the other hand, if Josh's *very* generous offering solves the problem...

Link to comment

Assembly,

My rewrite left D2_Framing intact ? all you need to to is put your profile code in that procedure, and unless I'm misunderstanding what you are trying to do, that should be exactly what you want.

As I mentioned before, I suspect the reason the code fails as a PIO is that function D3_Studarray doesn't just define a profile, it draws the profile as the 2D component of the PIO. CreateDuplicateObject is likely getting into trouble copying the only 2D component of the PIO to the 3D component.

Maybe consider putting the profile into the PIO profile (CustomObjectProfileGroup). You can set a profile group for any PIO, not just a path PIO.

You may also be running into trouble when the PIO is drawing it's placement preview. I believe it only draws the 2D portion in 2D view and the 3D portion in the 3D view. It's possible if you are placing the PIO in 3D view, the 2D portion is not actually rendering and cannot return a handle.

My method only draws the 3D object, so I believe it will help either of the possible 2D/3D issues.

If you really want to troubleshoot the code you have, find unique names for global and local variables. Instead of constantly redefining the profile handle as a new local variable, you may be safer defining it as a global variable, and using the gVar every time you need the profile instead of constantly passing it around.

HTH,

Josh

Link to comment

Thanks for the help on this... Let me outline the broader picture of this.

None of the PIO will be used inside walls, they are stand alone 3D objects.

This is not using paraent Child PIO's.

I do a lot of 3D Geometery scripting. I am working on a 3D detailing tool. There are many components to be created and moved into place. Things all have in common, is that

1) Objects are create at the origin, rotated to Correct Orientation, then moved to place.

2) All but a few 3D objects are extrudes.

I don't fully understand Object Oriented Code, I do like the idea that you can pass something to an object and get a result with out needing to get down into the subcode.

Considering both above, the only difference in most of my 3D objects is the profile. Thus I want code where I can pass the handle of a profile into a function to get a 3D object result.

I fly solo on my code thus I am lazy on commenting. To me the structure is logical thus as Joshua pointed out my Function Names do a lot for my commenting. I really do appreciate Joshuas assistance and suggestion, however while this will make this object work it is not the solution that fits my strategy.

I take on the variable comments and will work this back through the base code to separate from the Globals.

I have used this code base through some pretty complex Menu tools. It is when I move the code into a PIO it locks up on the

Create3Dobj(h: HANDLE; z, dZ: REAL): HANDLE

Following the Debugger the code does pass through this function 5 times before it crashes. It is almost as if it is the final stage just as the screen is about to regenerate that it hangs. I will refine the code down to an easier read and debug a couple more times and provide more detail.

Thanks everyone.

Link to comment

Just to be clear ? VS is not an Object Oriented language ? it's based on plain vanilla modular Pascal. Not sure if that's muddling your thinking. VS creates objects in the drawing, but it as not an object oriented language.

I think you have two ideas of the profile going, and that's making your code unduly complex: the profile as code in a function and the profile as an object in the drawing.

If the profile is a function or procedure (in your case here the rounded rectangle), you don't need to pass a handle to an instance of the profile in your 3D function. All you need to do is call the profile procedure/function while drawing your extrude. Think of it this way: Rect(x1, y1, x2, y2) is actually a procedure, just like your profile procedure. It's just already defined for you.

Some VW 3D functions require a profile object, like CreateTaperedExtrude. In that case, in a PIO, you want to either put the profile in the object's profile group and refer to it with a global variable, or call the profile's creation code, make the extrude, then delete the profile.

-Josh

Link to comment

Assembly, you are using a variant of my sub for 3D object creation. That routine I use since years, in many PIOs. If used properly it doesn't create problems.

A couple of notes:

- If you care about origin, be aware that while you are in a PIO you can't see the user origin shift. The PIO is in its own world. Don't mess up with origin by script.

- There are differences -and there are always been- according to how you run a script: by palette, by menu, by applescript or if it's PIO. These differences are on routine-basis, if you use BeginContext, but also and particularly the compiler.

- PIOs are also different in the sense that they have multiple regens, the code doesn't run only once, it can run many times.

You need now to create a basic pio with only an alert. Please experiment with all various options:

* click on tools palette

* placement on drawing (IsNewCustomObject)

* reset existing instance by parm change (simplest user edit)

* duplicate

* copy and paste in a new document

* wall insertion

* regen coerced by wall changes (this gets rather tricky on texturing)

* placement with CreateCustomObjectPath, according to the running VW version.

* has profile groups

* is event enabled or not

* has reset on move/rot or not

* has reset on other special events or not and here you can spend a long time in searching for all possible quirks of events/special props according to the parent container.

* ....

These are some of the things you need to check for avoiding problems.

You can't transfer the code of a menu straight off to a PIO. I don't see any "IF GetCustomObjectInfo(gPioN, gPioH, gPIOrecH, gWallrecH) THEN... ". You need that in order to avoid the code to execute when a forced regen is not needed, or wish to execute something else.

So don't look at the memory allocated, is none of our business and we can't do a thing about it anyway. You need to look at your handles.

The code needs to change, Assembly. It doesn't help you to stick to it, because is not OK.

Please compare the original H_Create3Dobj from Vectorlab with your one.

You can observe that

* you create a temporary line but don't delete it

* you assign this extruded line as result to Create3Dobj, but actually don't really use it. You also assign the handle before inserting the new obj in the extrude. But this doesn't harm, because....

* you use a global variable htemp as result for CreateDuplicateObject.

So actually you have no idea where your extrude is going, what it is (it's a line with some other shape) and which is the handle, global temp (* fear *). You don't need that function, but to make problems, with your changes.

FUNCTION Create3Dobj(h: HANDLE; z, dZ: REAL): HANDLE;
  BEGIN
     IF h <> NIL THEN BEGIN
        BeginXtrd(z, dZ);
               MoveTo(0,0);
           LineTo(1, 1);
        EndXtrd;
                Create3Dobj:=lnewobj;        
                htemp:=CreateDuplicateObject(h, LNewObj);
     {   DelObject(FIn3D(GetParent(CreateDuplicateObject(h, LNewObj))));}

     END;
  END;

{ Orso **************************************** }
{ creates an extrude from a HANDLE h, preserving the original h. Returns a handle to the extrude }
FUNCTION H_Create3Dobj(h: HANDLE; z, dZ: REAL): HANDLE;
BEGIN
	IF h <> NIL THEN BEGIN
		BeginXtrd(z, dZ);
		Line(1, 1); { just draw something for creating an extrude container }
		EndXtrd;

		DelObject(FIn3D(GetParent(CreateDuplicateObject(h, LNewObj))));
		{ places a Copy of h in the extrude and Deletes the line }

		H_Create3Dobj := LNewObj;
	END;
END;

Link to comment

Again Thanks to Everyone.

I have written in testing procedures to report back on what is happening. It is strange.

If i double click on the PIO tool I can create the object in a file, and I can edit the object.

If I click inside the drawing then I get a Crash.

This is the revised code.

http://pastebin.com/Yf0FZGn7

This is the returned testing file.

http://pastebin.com/GiFjYJS3

- PIOs are also different in the sense that they have multiple regens, the code doesn't run only once, it can run many times.

You need now to create a basic pio with only an alert. Please experiment with all various options:

* click on tools palette

* placement on drawing (IsNewCustomObject)

* reset existing instance by parm change (simplest user edit)

* duplicate

* copy and paste in a new document

* wall insertion

* regen coerced by wall changes (this gets rather tricky on texturing)

* placement with CreateCustomObjectPath, according to the running VW version.

* has profile groups

* is event enabled or not

* has reset on move/rot or not

* has reset on other special events or not and here you can spend a long time in searching for all possible quirks of events/special props according to the parent container.

* ....

Orso. Thanks for the list of things to test. It seems I get locked on the first instance.

Double click on Tools Palette is okay.

Placement in the Drawings Crashes VW

Once in drawing I can edit- the editing updates the Testoutputfile.

I can Duplicate- the Duplicate updates the Testoutputfile.

I can cut and paste a generated object into a new file- This updates the testoutputfile.

Changing the PIO object Reset on Events makes no difference

I can create by double clicking tool pallet but not on clicking in the drawing.

AHHHHH HA!.

If I comment out the GetView and SetView it works!.

I think I found it!!!.

Well at least the testing procedures have been really useful to see how the code executes.

Again thanks to those who helped me out.

Link to comment

Just time for a quick reply:

In addition to making your object event enabled, you should look at creating a custom event handler. I have a PIO which uses get/set view, but it only does so upon regeneration. Head over to www.vectorlab.info for some good models and examples.

There is a preference to determine if the PIO is rendering for it's insertion preview. I don't have the number on hand, but you should be able to find it either in the VS appendix, searching this list, or at vectorlab.

For example (roughly):

IF NOT GetPre(xxx) THEN BEGIN...

hth,

Josh

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...