Start a new topic

New API user No Clue what im doing.

New to the API, learning a little but really struggling on how to even think of a way to do more complicated tasks.


What I am wanting to do:


inside the master.flt

find the lower left vertex of the tile filename0_0

translate all the tiles in the master.flt from said vertex to 0,0,0

save file


I'm really trying to learn how to do too many things at once, and not really succeeding on grasping the basics. I can look for older scripts, pick and pull and make a few things work, but if I don't have a file to reference, I'm pretty much lost.


any help would be greatly appreciated.



Hi John,


Your script can be broken down into a few steps


  1. Open master
  2. Find and Open filename0_0
  3. Get lower left vertex position of filename0_0
  4. transform that vertex position based on any xforms above it
  5. translate all tiles in master based on that calculation
  6. save and close everything


In this situation, we can make things more simple with a few assumptions.

If we assume that the db is open in Creator, we don't have to save and close the db. This little step makes the code less prone to errors and it makes it work in our Batch Run Script tool. 

Note: Batch Run Script will let you take a script that functions on the current db and apply it to lots of files and even folders of files. it takes care of opening and saving these files. It also allows for Creator tools to be invoked in the script.


With this simplification, the script will now only need to:


  1. get current db
  2. find smallest coordinate in world space
  3. transform the first child of db (assuming it is the only child)

 

#-------------------------------------------------------------------------
# First I am going to get the current db. I am assuming this is the master
# This assumption makes the code easier and it makes it more usable.
# It is more usable because it means this script can be run inside
# of the batch run script tool and applied to multiple databases in batch.
#-------------------------------------------------------------------------

db = mgGetCurrentDb()

#-------------------------------------------------------------------------
# Now let's find the lower left vertex. Instead of doing what you desribed
# I decided to get the lower left vertex of all the tiles. This makes it
# more flexible. The script would not depend on a particular file's tile
# names.
#-------------------------------------------------------------------------

MasterSpaceMin = mgMakeCoord3d (0,0,0)  # this will hold our lowest x,y,z
FirstCoordSet = False                   # this will tell us if we have a valid x,y,z

# This function is called for every node in the master and in the xrefs. 
# Even vertices are visited. It also maintains a matrix stack of any transforms
# above the node.
# MWALK_MATRIXSTACK - tells mgWalk to maintain a matrix stack so we can use it in the function
# MWALK_VERTEX - tells mgWalk to visit vertices
# MWALK_MASTER_ALL - tells mgWalk to visit all external reference nodes

def FindSmallest (db, parent, rec, userData):
   global MasterSpaceMin
   global FirstCoordSet
   
   ok, mat = mgWalkGetMatrix(userData)
   if mgGetCode(rec) == fltVertex:      
      # we have a vertex and the matrix that is transforming it,
      # convert the vertex coordinate to a world coordinate
      ok, x,y,z = mgGetVtxCoord(rec)
      localCoord = mgMakeCoord3d(x,y,z)
      worldCoord = mgCoord3dTransform(mat, localCoord)
      
      # we have teh world position of this vertex, update our MasterSpaceMin
      if not FirstCoordSet:
         MaseterSpaceMin = worldCoord
         FirstCoordSet = True
      else:
         if MasterSpaceMin.x > worldCoord.x:
            MasterSpaceMin.x = worldCoord.x
         if MasterSpaceMin.y > worldCoord.y:
            MasterSpaceMin.y = worldCoord.y
         if MasterSpaceMin.z > worldCoord.z:
            MasterSpaceMin.z = worldCoord.z
   return MG_TRUE
         
mgWalk(db, FindSmallest, None, None, MWALK_VERTEX | MWALK_MATRIXSTACK | MWALK_MASTERALL )

#-------------------------------------------------------------------------
# Now we should have the lowest corner of the entire set of tiles stored in
# the variable MasterSpaceMin and it is in world space. Now we have to 
# translate all the tiles below it using this value. The easiest way to do
# this is to add a transform to a parent node to all the children
#-------------------------------------------------------------------------

g1 = mgGetChild(db)
xform = mgNewRec (fltXmTranslate)
mgSetCoord3d (xform, fltXmTranslateFrom, MasterSpaceMin.x, MasterSpaceMin.y, MasterSpaceMin.z)
mgSetCoord3d (xform, fltXmTranslateDelta, -MasterSpaceMin.x, -MasterSpaceMin.y, -MasterSpaceMin.z)
mgAttach(g1, xform)

 

The basic functions that are most vital to understand:


mgWalk

mgSetAttList / mgGetAttList


These functions are the core of 90% of all scripts you will come across. Taking the time to fully understand them will greatly benefit your scripting. In this situation, we didn't need to use mgGetAttList because we used mgGetCoord3d which is a similar function but specific to mgcoord3ds. Even so, if you were wondering where the fltXmTranslateFrom and fltXmTranslateDelta values came from, these types of functions have an entire document called the data dictionary that describes every possible parameter that can be used to access data in nodes.

thank you sir, I am hand jamming this over to my workstation. have run into a few errors, im working through those atm.


For some reason, I cannot follow along the Reference guide, but I can open a script up and figure out what it is doing and pick,pull,apply it to what I need it to do. I really only started working with the API about 3 weeks ago. I am understanding it more and more daily, but I was stuck and getting nowhere. 


I will let you know how it goes here shortly.

worked through some missed characters and alignment issues and it moved everything to the right place except for Z. looking to see what i can figure out 

ok, the script is set to move z to the lowest z value. You can prevent moving z alltogether by modifying two lines of code. Change the z values of both mgSetCoord3d functions to zero.

mgSetCoord3d (xform, fltXmTranslateFrom, MasterSpaceMin.x, MasterSpaceMin.y, 0)
mgSetCoord3d (xform, fltXmTranslateDelta, -MasterSpaceMin.x, -MasterSpaceMin.y, 0)

 

replacing the MasterSpaceMin.z's with 0 set the tiles higher up than leaving the Spacemins alone. Im trying to get vertex to touch x,y,z at 0



I see. The script as written tries to put the lower left bounding volume of the tile at 0,0, not any particular vertex. It is a little more complicated to do what you are asking because there is no clear way to decide what vertex is best. If you just want any vertex from one of the tiles put there, it would be easy to just take the first vertex found and use it

yeah, I was thinking it could just find the vertex on the bottom left of a specific tile and move everything else with it. 

Finding the bottom left would just need some more math. 

  • First you have to find the bottom left corner of the bounding box
  • Then you need to find the top right of the bounding box
  • Then you need to make a line from the bottom left to the top right
  • Then loop through every vertex and project it onto this line to see the closest one to the bottom left

The script I sent already calculates the bottom left corner of the bounding box by finding the min
The same thing can be done in reverse to find the top right by finding the max
Then you can create a vector from min to max
A second walk could be called with a different function to compare to this line.

The comparison would be a dot product between the vector (min,  max) and the vector (min, pt) where pt is the current vertex position
This would produce a single value and you can use this to determine the smallest of these values
Then you take the point that was used to make that smallest value and use it as the the bottom left.

ok, let me wrap my head around what we have so far and I will see what I can come up with. Thank you for the help already. I will post back what i come up with

ok, so I just copied everything with min

 pasted in the editor

renamed all the mins to max swapped the > with < for the max z

setup new def, for a max set

new mg_walk

new mgsetcoord3d for the max data


so close..its just over 21m off in the negative z..


will keep going

skipped over the part on getting a vector value


will hit this in the am. again, thanks for getting me started in the right direction.

tried again before i left for home. I got the one tile to move to the correct location using the script by trying it on a specific tile by itself. but once I try on the master.flt, same results as before. I will sleep on it.  

I thought of an easier way than testing along the center line would be to to instead test all vertices based on distance to the min point already calculated with the script.

Try this out:


 

#-------------------------------------------------------------------------
# First I am going to get the current db. I am assuming this is the master
# This assumption makes the code easier and it makes it more usable.
# It is more usable because it means this script can be run inside
# of the batch run script tool and applied to multiple databases in batch.
#-------------------------------------------------------------------------

db = mgGetCurrentDb()

#-------------------------------------------------------------------------
# Now let's find the lower left vertex. Instead of doing what you desribed
# I decided to get the lower left vertex of all the tiles. This makes it
# more flexible. The script would not depend on a particular file's tile
# names.
#-------------------------------------------------------------------------

MasterSpaceMin = mgMakeCoord3d (0,0,0)  # this will hold our lowest x,y,z
FirstCoordSet = False                   # this will tell us if we have a valid x,y,z

# This function is called for every node in the master and in the xrefs. 
# Even vertices are visited. It also maintains a matrix stack of any transforms
# above the node.
# MWALK_MATRIXSTACK - tells mgWalk to maintain a matrix stack so we can use it in the function
# MWALK_VERTEX - tells mgWalk to visit vertices
# MWALK_MASTER_ALL - tells mgWalk to visit all external reference nodes

def FindSmallest (db, parent, rec, userData):
   global MasterSpaceMin
   global FirstCoordSet
   
   ok, mat = mgWalkGetMatrix(userData)
   if mgGetCode(rec) == fltVertex:      
      # we have a vertex and the matrix that is transforming it,
      # convert the vertex coordinate to a world coordinate
      ok, x,y,z = mgGetVtxCoord(rec)
      localCoord = mgMakeCoord3d(x,y,z)
      worldCoord = mgCoord3dTransform(mat, localCoord)
      
      # we have teh world position of this vertex, update our MasterSpaceMin
      if not FirstCoordSet:
         MaseterSpaceMin = worldCoord
         FirstCoordSet = True
      else:
         if MasterSpaceMin.x > worldCoord.x:
            MasterSpaceMin.x = worldCoord.x
         if MasterSpaceMin.y > worldCoord.y:
            MasterSpaceMin.y = worldCoord.y
         if MasterSpaceMin.z > worldCoord.z:
            MasterSpaceMin.z = worldCoord.z
   return MG_TRUE
         
mgWalk(db, FindSmallest, None, None, MWALK_VERTEX | MWALK_MATRIXSTACK | MWALK_MASTERALL )

#-------------------------------------------------------------------------
# This section will find the closest vertex to the MasterSpaceMin point
# that was calculated above.
#-------------------------------------------------------------------------

bestVertex = mgMakeCoord3d(0,0,0)
bestVertexDistance = 0
bestVertexSet = False

def FindClosest (db, parent, rec, userData):
   global MasterSpaceMin
   global bestVertex
   global bestVertexDistance
   global bestVertexSet
   
   ok, mat = mgWalkGetMatrix(userData)
   if mgGetCode(rec) == fltVertex:      
      ok, x,y,z = mgGetVtxCoord(rec)
      localCoord = mgMakeCoord3d(x,y,z)
      worldCoord = mgCoord3dTransform(mat, localCoord)
      
      dist = mgCoord3dDistance(worldCoord, MasterSpaceMin)
      
      # we have the world position of this vertex, update our MasterSpaceMin
      if not bestVertexSet or dist < bestVertexDistance:
         bestVertex = worldCoord
         bestVertexDistance = dist
         bestVertexSet = True

   return MG_TRUE
         
mgWalk(db, FindClosest, None, None, MWALK_VERTEX | MWALK_MATRIXSTACK | MWALK_MASTERALL )


#-------------------------------------------------------------------------
# Now we should have the lowest corner of the entire set of tiles stored in
# the variable MasterSpaceMin and it is in world space. Now we have to 
# translate all the tiles below it using this value. The easiest way to do
# this is to add a transform to a parent node to all the children
#-------------------------------------------------------------------------

g1 = mgGetChild(db)
xform = mgNewRec (fltXmTranslate)
mgSetCoord3d (xform, fltXmTranslateFrom, bestVertex.x, bestVertex.y, 0)
mgSetCoord3d (xform, fltXmTranslateDelta, -bestVertex.x, -bestVertex.y, 0)
mgAttach(g1, xform)

 

Login to post a comment