API - hole setPositionByPlaneAndOffsets - bug(?)

API - hole setPositionByPlaneAndOffsets - bug(?)

pludikar
Collaborator Collaborator
7,457 Views
40 Replies
Message 1 of 41

API - hole setPositionByPlaneAndOffsets - bug(?)

pludikar
Collaborator
Collaborator

Repost - Apologies - I accidently posted this in the API forum (here)

 

I'm trying to set the location of a hole a fixed distance from 2 sides of a corner, using 

returnValue = holeFeatureInput_var.setPositionByPlaneAndOffsets(planarEntity, point, edgeOne, offsetOne, edgeTwo, offsetTwo) 

 

I can get this to work as expected on an occurrence, but when the Occurrence has either been moved (with position capture) or is located via a join, then the direction of the two offsets appear to be unpredictable.  This results in the hole being placed in the wrong quadrant, but depends on the actual location of the corner.

 

I have definitely placed the initial guess position (point) correctly, and the final hole center should be exactly on the guess point - so the positioning algorithm should resolve to an immediate solution.  I created a sketch and visually confirmed that the location of the initial guess point is where I expected it to be.  Both offsets are the same and positive.  Hole centers on unmoved, and non-joined occurrences are also exactly where I expected them to be - on the sketch point.

 

I suspect this is a bug.  If it isn't, could you provide a code example based on occurrences.

 

Thanks

I'm not an expert, but I know enough to be very, very dangerous.

Life long R&D Engineer (retired after 30+ years in Military Communications, Aerospace Robotics and Transport Automation).
7,458 Views
40 Replies
Replies (40)
Message 2 of 41

pludikar
Collaborator
Collaborator

It seems that support forum automatically pushes API issues and bugs here - very confusing!

I'm not an expert, but I know enough to be very, very dangerous.

Life long R&D Engineer (retired after 30+ years in Military Communications, Aerospace Robotics and Transport Automation).
0 Likes
Message 3 of 41

pludikar
Collaborator
Collaborator

 I found the problem, and there's no issue with hole setPositionByPlaneAndOffsets method.  There is, I believe, a significant bug in the way proxy positions and locations are determined.  The way I've understood the user manual is that occurrences and their proxies take care of all calculations regarding position.  If it does, then I'm missing something, and I've not found it.   

 

Try as I may, I could not get a hole to be created correctly in anything but the original version of a component (Componentx:1).  If I made a copy of a component, then either moved it or attached it with a joint, I could not get the holes to align.  I tried creating proxies using nativeObject.createForAssemblyContext and occurrence.assemblyContext as well as using

holeFeatureInput.creationOccurrence - Nothing seemed to work as expected. 

 

Using holeFeatureInput.setPositionByPlaneAndOffset(plane, initial position, edge1, offset1, edge2, offset2) - It took me a while to realise why holes were being formed in the wrong quadrant.  The initial position was not where I expected it to be.  What was happening was the position of holes was referenced to the coordinate space of componentx:1, but actually in the coordinate space of the component that was being used.  So, for example, if component1:1 origin was at (x:0,y:0) and component1:2 was located at (x:10,y:10).  If I wanted to put a hole in component1:2(x:5,y:5) it should have placed it at (x:15, y:15), but in practice it put it at (x:25, y:25) ie. component1:2 origin + offset from component1:1

 

My work around - do all feature positioning relative to componentx:1

 

name = face.assemblyContext.name.split(':')[0]+':1' #occurrence is supposed to take care of positioning

occ = self.rootComp.occurrences.itemByName(name) # this is a work around - use 1st occurrence as proxy

face = face.nativeObject.createForAssemblyContext(occ)

 

If I've totally missed something, I'd be happy to be corrected, but as I've not had any kind of response from the forum in the past few weeks, I'm guessing no one knows any better.

 

if anyone is interested in my working code, you can find it here on github

 

Regards

Peter

 

I'm not an expert, but I know enough to be very, very dangerous.

Life long R&D Engineer (retired after 30+ years in Military Communications, Aerospace Robotics and Transport Automation).
0 Likes
Message 4 of 41

prainsberry
Autodesk
Autodesk

Hey Peter,

 

Just seeing this.  Very cool what you are doing here. I am by no means an expert on the inner workings of the API, but as an avid user i can tell you that i have many times struggled with ensuring i am in the correct context when attempting to create features.  I am not sure if this is a bug, I think some more testing may be required.  

 

I was looking at the master branch on your giuthub page so i don't think i am seeing exactly what wasn't working.  I think the problem may lie with the guess point.  When you get its coordinates i think that you are getting them in the component's coordinates, not world coordinates.  I try playing with some different ways to actually capture that point?  Maybe jsut make a test where you pace a sketch opr reference point to make sure what ever method you are using is placing the guess point in the correct space.  I think what you want to do is createForAssemblyContext on the start_vertex.  Maybe try testing placing points in both locations?  

 

I think it might also be better to allow the selection of all the faces, then process the edges after the user executes the command?  Then you won't ahve the issues you are seeing with losing references?  

 

As a fellow enthusiast i would be happy to jump on a web meeting or something to look at a few things in more detail.  



Patrick Rainsberry
Developer Advocate, Fusion 360
0 Likes
Message 5 of 41

pludikar
Collaborator
Collaborator

Hi Patrick,

 

I'm very familiar with your work, I learned a lot from your tutorial youtube videos.  I'm one of your many fans 🙂

 

The issue I think is line 334 in the main file:

 

holeInput.creationOccurrence = face.assemblyContext #this parameter doesn't appear to work!!

I tried various values and checking hole.assemblyContext after the hole is created 

 

hole = holes.add(holeInput)

 

- it's possible that I missed something, but I could not get hole.assemblyContext to give me anything but 'None'.  If this is what it is supposed to be, then it's less intuitive than I was expecting.  Getting the right coordinate system is definitely a challenge, and took a bit of work to get my head around it.  I think I've got it, but that may be a delusion.  I also created a sketch plane and plotted the initial points - they were definitely in the right place, until the holes were created - Hmm?

 

I was in two minds when I opted to include the edge calculation during the selection process.  I've arranged for this to actually only happen once - the first time the mouse moves over a face - thereafter the selection is preloaded without going through the calculation again.  When I first did it the mouse was almost impossible to use because it was hesitating with every movement, now it's actually quite usable.  It may not be for everyone, in which case it's easy to change.  I was hoping to make it persistent by using attributes, I was almost there, but found I was fighting the fact that changing attributes seems to inValidate any entities it's associated with.

 

The reason I finally went with including edges was because if I selected a face I was more likely to want to keep all the dogbones, and if I didn't, there would only be a few I'd want to unselect.  Much easier than selecting edges individually - however time will tell if that's the better approach.  With this approach that's what I can do.  The downside with this appraoch is that it can sometimes take a second or two for the associated edges to be processed.

 

As an ethusiast I would be delighted to work with you.  I'm retired and I'm gearing up to make many cabinets and other bits and pieces with my 4'x8' CNC router for a major renovation my wife wants:-)  I think F360 is missing a big market with wood/panel work, not having the dogbones and not being able to nest is IMHO, a short fall.  I was working on translating a public domain genetic algoritm from javascript to python to fill the gap, but I've been distracted away from that for a while - see svgnest.com  I have an Engineering background, having started with 8 bit microprocessors where every bit of memory and every machine code cycle counted, so that'll give you an idea how long I've been around.

 

Regards

Peter

I'm not an expert, but I know enough to be very, very dangerous.

Life long R&D Engineer (retired after 30+ years in Military Communications, Aerospace Robotics and Transport Automation).
0 Likes
Message 6 of 41

prainsberry
Autodesk
Autodesk

Haha thanks!!

 

So its kind of weird and the whole concept of assembly context is really interesting.  Very powerful but always difficult to tell where you are sometimes.

 

So the hole feature is probably something that is not in an assembly context when it is returned from the creation method.  What is returned from the holeFeatures.add() method is the native object. Remember the feature exists in the component it is being added to, which is why it would instantly show up in all copies (occurrences) of that component.

 

I don't think setting the creation occurrence will matter since the geometry you are referencing is in the same component as the hole.  I still think it might be that you need the proper context of the vertex you are using for the origin point of the guess before you do the translation of the point.  

 

Try adding this to the start_vertex:

bRepVertex_var.createForAssemblyContext(occurrence)  

 



Patrick Rainsberry
Developer Advocate, Fusion 360
0 Likes
Message 7 of 41

pludikar
Collaborator
Collaborator

Hi Patrick,

 

To all intents and purposes that is exactly what I'm doing in the loop starting at line 322.  Everything is in the context of the chosen occurrence, so when I translate the initGuess point, I'm doing it relative to the start vertex.  The point gets translated by a scaled normalized vector in two directions, so it is still in the same context as the original vertex.

 

The way I visualise Components, Occurrences and NativeObjects is (I'm sure someone will correct me if I'm off base):

 

  • The real object is the nativeObject, but it has it's own internal coordinate space, but it has absolutely no idea where it is.  Let's say its origin can be identified by a point A.  Internal geometry of the nativeObject is relative to point A.
  • That is where Occurrences come in.  An Occurrence adds a wrapper that, from the outside, make the nativeObject look like its origin is at point B. 
  • When you want to interact with an occurrence, somehow you need to rationalize the coordinate systems.  Things will quickly go haywire unless if you use the same coordinate system for all calculations.  So from the outside you will be dealing with a vector B + A.  Quite simply the Occurrence wrapper will effectively subtract the B vector, when making calculations internally to the nativeObject, and it will add the B vector when it is observed from the outside.
  • Another way to visualize this is using UTC (Coordinated Universal Time).  West coast of USA is UTC-8, East coast is UTC-5.  If it's 12 noon PST, it'll be 3pm EST - however, if you're looking down from the moon you'd say the time is 8pm UTC, and both zones will know what you are talking about.  The wrapper around the West Coast subtracts 8, while the wrapper around the East Coast subtracts 5.
  • A component is really a collection of Occurrences - it keeps all the information related to the occurrences (and hence the nativeObject) in one place that's easy to access.
  • As long as the interactions are done in the context of the Occurrence, everything, I understand, should be taken care of.

The symptoms I was seeing was that holes were being placed off it's target point by the same offset as the occurrence I was trying to process.  That indicates to me that the B vector subtraction wasn't taking place.  Either the wrapper isn't working, or I'm doing something I shouldn't be.  No one has yet been able to tell me I'm doing something wrong (but that person may not have arrived on the scene yet 🙂 )

 

I'm travelling tomorrow, so I won't be able to repond until I get home.

 

Regards

Peter

 

Regards
Peter

 

I'm not an expert, but I know enough to be very, very dangerous.

Life long R&D Engineer (retired after 30+ years in Military Communications, Aerospace Robotics and Transport Automation).
0 Likes
Message 8 of 41

prainsberry
Autodesk
Autodesk

yah i did some little test with a script and it is not that vertex as i thought.  I still have to imagine somewhere in there you are somehow getting back into the component space.  

 

I made this quick little script to test a couple things and I am getting a weird result, although not the same as yours.  The hole is in the right place, but it doesn't show the geometry cut.  Then if you exit the feature and hit ok it updates.  If you put the hole in occurrence 1 then it shows up right away.

 

https://github.com/tapnair/vertexContext

 

 

I thought i could figure it out quickly, but no such luck.  

 

Maybe next week we can do a web meeting and take a closer look.

 

Do you have a branch of your code where you are still getting the error and not re-referencing the 1st occurrence?

 



Patrick Rainsberry
Developer Advocate, Fusion 360
Message 9 of 41

pludikar
Collaborator
Collaborator

Hi Patrick,

 

I created a branch 'Without-workaround'.

 

I've also been working with the code to see if there's anything I can determine.

 

I would say that, in general, the API is far more complicated than it needs to be.  I suspect even more strongly that  line 334 (holeInput.creationOccurrence = face.assemblyContext) doesn't do what I think was intended.  If you add a modification to hole (after line 339)  - hole.createForAssemblyContext(occ) then the hole appears to be added to the right occurrence, but not in the right position.

 

It also seems that the 3DPoint I create with initGuess, doesn't easily get converted into the right coordinate system.  All other entities can be converted using createForAssemblyContext, or similar - there is no obvious way to do that with a 3DPoint.  I would suggest that is a vital missing feature.

 

Another problem I've also found is that the face.tempId I use to recall the edge-face Associations during the SelectionEvent isn't unique to the face occurrence.  The frustrating thing is that many other features are unique - attributes, for example.  The attribute set on one face of an occurrence is different to the attribute on the same face of another occurrence.  So, I think you are right that the edge selections are going to have to be done after either clicking on a face, or during execution - at the moment I prefer the former.

 

 

PM me with your free time schedule this week - and I'll be happy to get on a call with you.

 

Peter

I'm not an expert, but I know enough to be very, very dangerous.

Life long R&D Engineer (retired after 30+ years in Military Communications, Aerospace Robotics and Transport Automation).
0 Likes
Message 10 of 41

pludikar
Collaborator
Collaborator

Hi Patrick,

 

I've added a new version in a branch called "working with nativeObjects".  This version seems to work, with everything except mirrored components, where holes are placed in the right location but do not appear after processing.

 

Peter

I'm not an expert, but I know enough to be very, very dangerous.

Life long R&D Engineer (retired after 30+ years in Military Communications, Aerospace Robotics and Transport Automation).
0 Likes
Message 11 of 41

prainsberry
Autodesk
Autodesk

Wow the time really got away from me today, was hoping to dig into this.  

 

Yah I agree it can be challenging to know context.  Like a 3D point would never have context because it is just an XYZ location (in some coordinate space), where as a vertex does have context because it could be the location of the of the vertex in global coordinates of any one of a number of occurrences that have been transformed (or mirrored).

 

WRT to the behavior you are seeing with mirrored components and the hole being placed correctly, but not showing up.  I saw the same behavior in my simple test case.  I think this may be a bug.  If you edit the definition of the hole after it is created and simply hit ok, then the hole appears?

 

I am curious to look at the difference in your native object version and the one with the failure to see at what point the logic breaks down on the assembly context.

 

Also one other point.  In a previous post you mentioned about how the holeFeatureInput.creationOccurrence didn't seem to do what it was supposed to do.  I have seen another place in the API, i believe it was in creating jointInput's, where there was a similar behavior.  It's like the feature can't actually calculate something until after it has actually been created.  I can't remember the exact reason that was given to me, but in that case the solution (unfortunately) was that you basically had to create the feature then go back and edit it sop that it had actually computed its result already in order to change the particular value.  I am wondering if this is a similar situation.  It is not until after the hole is created that it can properly compute which occurrence is being referenced.   

 

 

 

 



Patrick Rainsberry
Developer Advocate, Fusion 360
0 Likes
Message 12 of 41

pludikar
Collaborator
Collaborator

I would love to see API examples of adding features etc. Unfortunately every example in the sample programs is based only on rootComponent - you should get your team to create some examples of handling all permutations and combinations of rootComponent bodies, Components, Occurrences and nativeBodies.  Get them to add this on their todo list:-)

 

In my primitive view of the world I like to try to keep things simple and consistent.  To this end I would expect any value you put in holeInput.creationOccurrence to have exactly the same result as hole.createForAssemblyContext.  Maybe the API isn't intended to do this, but I see the holeInput as equivalent to a script, so when a hole is added it just looks up the script and creates a hole according to the instructions.  If using holeInput is different to modifying the hole directly, then I would classify that as a bug (if it's not a bug, then it's not a consistent and intuitive design)

 

The same goes for using the 3DPoint.  As it's 100% derived from an existing vertex, it should also be handled the same as the vertex.  At the moment, the implication is that setPositionByPlaneAndOffsets can only be used with an existing vertex, or you have to use construction points.  The initial Position shouldn't accept a 3DPoint if it can't be used.  There are numerous occasions when you need to create a point outside a body - if it can't play nice with Occurrences, then why have the ability?

 

In my last revision, I processed all the holes, offsets, faces, edges and bodies in the nativeObject context, but the hole feature was associated with the component - I don't think it's hugely different to using Occurrence:1 as I did before, but it appears to give a more consistent result.  The concept of proxies is supposed to simplify the API, but IMHO it's missed the mark - it's made unnecessarily complicated.  As a developer you shouldn't need to think which context am I on - that's the job of the software as long as you are dealing apples to apples - in other words, if you have nothing but proxies everything should play together.

 

I get the same effect for dogbones in mirrored components/occurrences - holes are created without error, in the right place and if you edit the hole, the hole appears after clicking OK.  

 

Peter

 

 

I'm not an expert, but I know enough to be very, very dangerous.

Life long R&D Engineer (retired after 30+ years in Military Communications, Aerospace Robotics and Transport Automation).
0 Likes
Message 13 of 41

pludikar
Collaborator
Collaborator

@prainsberry

 

Hi Patrick,

 

In case you are still interested, I've updated the GIT master.  For the most part, it seems to work, but occasionally it can't find the right body to figure out where to tool the hole.  It does that when using F360 directly too.  I've had to manually change the hole, on a case by case, basis to a fixed depth and it works - when that happens, the mouse won't even pick up a face to select.  Overall I'd say that it can be a bit fussy sometimes, other times it's fine - I think it depends on how the model was built in the first place.

 

I've also added filtering and selection control.  Once you select a face it will only allow you to select faces on parallel planes on the occurrence you are working on.  You can also unselect edges once they have been identified.  

 

Anyway let me know what you think

Peter

I'm not an expert, but I know enough to be very, very dangerous.

Life long R&D Engineer (retired after 30+ years in Military Communications, Aerospace Robotics and Transport Automation).
0 Likes
Message 14 of 41

pludikar
Collaborator
Collaborator

@prainsberry

 

I believe I now have a consistently working add-in - see screencast here

 

Peter

I'm not an expert, but I know enough to be very, very dangerous.

Life long R&D Engineer (retired after 30+ years in Military Communications, Aerospace Robotics and Transport Automation).
0 Likes
Message 15 of 41

prainsberry
Autodesk
Autodesk

Hey that is great to hear!!   Sorry i have been absent from the conversation the last couple weeks have been CRAZY busy with back to back travel as well as being gone personally over the weekends.  

 

I am looking forward to taking a look at how you came to a solution.

 

For the benefit of anyone who stumbles on this thread in the future, what was the essence of the solution?  How did you ensure you were referencing and measuring from the correct occurence and coordinate system?

 

How were you able to get around the issue of the holes not appearing in occurrences other than :1 ?



Patrick Rainsberry
Developer Advocate, Fusion 360
0 Likes
Message 16 of 41

marshaltu
Autodesk
Autodesk

Hello,

 

The issue would be because of the confusion which coordinate system initial guess point is located at. Ideally it should have same logic with other arguments(e.g. edgeOne, edgeTwo). Unfortunately it seemed that we always assume the initial guess point is located at the coordinate system which "planarEntity" is located at in our API implementation. 

 

For example of holeTest I attached, the second occurrence is moved from its origin. The following two block of codes will generate same result. In the first example, we use native body from sub component. The initial guess point will be located at the coordinate system of sub component. In the second example, we have to use native face to get a initial guess point in sub component.

 

FUS-38207 is logged to track the issue. We can probably change the behaviour (it would be a little risky if some clients have used the API) or add more detailed description in help document.

 

Thanks,

Marshal

 

import adsk.core, adsk.fusion, traceback

def run(context):
  ui = None
  try:
    app = adsk.core.Application.get()
    ui  = app.userInterface
    
    design = adsk.fusion.Design.cast(app.activeProduct)
    root = design.rootComponent
    
    holeFeatures = root.features.holeFeatures
    holeDiam = adsk.core.ValueInput.createByString('10 mm')
    holePosX = adsk.core.ValueInput.createByString('15 mm')
    holePosY = adsk.core.ValueInput.createByString('20 mm')
    tipAngle = adsk.core.ValueInput.createByString('180 deg')
    holeDepth = adsk.core.ValueInput.createByString('30 mm')

    occ = root.occurrences.item(1)
    body = adsk.fusion.BRepBody.cast(occ.bRepBodies.item(0)).nativeObject
    face = body.faces.item(0)
    pointOnFace = face.pointOnFace
    edge1 = face.edges.item(0)
    edge2 = face.edges.item(1)
    
    holeInput = holeFeatures.createSimpleInput(holeDiam)
    holeInput.tipAngle = tipAngle
    holeInput.setPositionByPlaneAndOffsets(face, pointOnFace, edge1, holePosX, edge2, holePosY)
    holeInput.setDistanceExtent(holeDepth)
    holeInput.creationOccurrence = occ
    
    holeFeatures.add(holeInput) 
    
  except:
    if ui:
      ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
import adsk.core, adsk.fusion, traceback

def run(context):
  ui = None
  try:
    app = adsk.core.Application.get()
    ui  = app.userInterface
    
    design = adsk.fusion.Design.cast(app.activeProduct)
    root = design.rootComponent
    
    holeFeatures = root.features.holeFeatures
    holeDiam = adsk.core.ValueInput.createByString('10 mm')
    holePosX = adsk.core.ValueInput.createByString('15 mm')
    holePosY = adsk.core.ValueInput.createByString('20 mm')
    tipAngle = adsk.core.ValueInput.createByString('180 deg')
    holeDepth = adsk.core.ValueInput.createByString('30 mm')

    occ = root.occurrences.item(1)
    body = adsk.fusion.BRepBody.cast(occ.bRepBodies.item(0))
    face = body.faces.item(0)
    pointOnFace = face.nativeObject.pointOnFace
    edge1 = face.edges.item(0)
    edge2 = face.edges.item(1)
    
    holeInput = holeFeatures.createSimpleInput(holeDiam)
    holeInput.tipAngle = tipAngle
    holeInput.setPositionByPlaneAndOffsets(face, pointOnFace, edge1, holePosX, edge2, holePosY)
    holeInput.setDistanceExtent(holeDepth)
    
    holeFeatures.add(holeInput)     
    
  except:
    if ui:
      ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

 

 



Marshal Tu
Fusion Developer
>
0 Likes
Message 17 of 41

pludikar
Collaborator
Collaborator

Hi @marshaltu

 

I’ve been trying to get this working since before Christmas.  InitGuess is always Relative to the coordinate space of the edges and face that I’m trying to use setPositionByPlaneAndOffset.  if my startVertex in at location (1,1,1) relative to the component origin and the face is on the (0,0,1) plane and I move the initGuess (-0.1,-0.1,0) relative - my initPoint will be at (0.9,0.9,1).

 

When the component origin is at (0,0,0) my initPoint will be (.9,.9,1). If I have an occurrence origin at (10,10,10), then initPoint will be located at (10.9,10,9,10).  But the hole gets placed at 20.9,20,9,20 the initPoint has nothing to do with the final hole placement. - no matter how you look at it, this is a Bug!  

 

The only way I could get the hole located properly is to bring everything down to the component/nativeObject coordinate space. 

 

In your example InitPoint = pointOnFace which is a Point3D. Point3D has no context other than world space. So, if you translate it by (-.1,-.1,0) it is the same I’m doing. It’s still in world space.

 

I am totally frustrated.  Please could you have a look at my code here  -  specifically around lines 539 to 561 - I can't believe what I'm trying to do is out of the ordinary. 

 

You can try changing the face and edges so that they are not nativeObjects.  I had to change them to nativeObjects to get the holes to be located in the right place.

 

Peter

 

 

I'm not an expert, but I know enough to be very, very dangerous.

Life long R&D Engineer (retired after 30+ years in Military Communications, Aerospace Robotics and Transport Automation).
0 Likes
Message 18 of 41

marshaltu
Autodesk
Autodesk
Hello,

Sorry for the confusion. In fact, I used "Component:2" (index is 1)in my sample. If you try index 2 or 3, you will get same result. The initial guess point is under coordinate system of native planar entity which hole is going to be created on.

It would be good if you can post a piece of codes and sample here to demo the issue you mentioned. Unfortunately I cannot find the problematic codes in your github project.

Thanks,
Marshal


Marshal Tu
Fusion Developer
>
0 Likes
Message 19 of 41

pludikar
Collaborator
Collaborator

@marshaltu

 

Thanks - I saw that you had used the 2nd occurrence.  This is the first time anyone has given me a reasonable example to look at - something I had asked for, a couple of months ago.

 

I will put some scripts together to demonstrate, but it will take me a day or two.  However, I will check that my init guess point is in the same coordinate system as the native (I assume you meant nativeObject) planar entity, in case this is something I missed. Although I believe that is what I am doing.

 

 

I will post when I'm ready.  

 

Peter 

I'm not an expert, but I know enough to be very, very dangerous.

Life long R&D Engineer (retired after 30+ years in Military Communications, Aerospace Robotics and Transport Automation).
0 Likes
Message 20 of 41

pludikar
Collaborator
Collaborator

 

Hi @marshaltu

 

The clue you gave me that the initPoint needs to be in the nativeObject coordinate space has helped.  But it means there is a "bug" in the description API reference:  

 

"A Point3D object that defines the approximate initial position of the hole. The point will be projected onto the plane. This point should be close to the final position of the hole and is used to determine which solution out of several possible solutions should be chosen for the hole location."  It should read "in the final position (in the nativeObject context) of the hole".  Otherwise this description is very misleading - you should add similar descriptions anywhere else the same type of situation occurs (eg component.findByUsingPoint()).  It's illogical to have one parameter in a totally different coordinate context to the others.  Much better to either make it very clear that it is different, or make it so that it's in the same context as the two edge parameters.

 

Unfortunately the example you gave is only the first layer of the onion, and a relatively simple case too.  When you have a more complex situation the approach appears to break down, particularly if you add .setOneSideToExtent() 

 

I've attached the model that I used to try my example.  If you uncomment lines 20, 21 - that should put holes in a component in an assembly context.  Toggling comments on line 51 and 52 will toggle .setOneSideToExtent vs .setDistanceExtent.  It's possible that my code is flawed, but I can't see it.  However, the oppFace appears to result in the face opposite to the one chosen for the hole.  Everything else should be a simple setting of holeInput parameters.

 

 

import adsk.core, adsk.fusion, traceback

def run(context):
  ui = None
  try:
    app = adsk.core.Application.get()
    ui  = app.userInterface
    
    design = adsk.fusion.Design.cast(app.activeProduct)
    root = design.rootComponent
    
    holeFeatures = root.features.holeFeatures
    holeDiam = adsk.core.ValueInput.createByString('10 mm')
    holePosX = adsk.core.ValueInput.createByString('1 mm')
    holePosY = adsk.core.ValueInput.createByString('1 mm')
    tipAngle = adsk.core.ValueInput.createByString('180 deg')
    holeDepth = adsk.core.ValueInput.createByString('30 mm')

    occ = root.occurrences.item(0)
 #    occ = root.occurrences.item(1)
    embedded = occ
#    embedded = occ.component.allOccurrences.item(1)
    body = adsk.fusion.BRepBody.cast(embedded.bRepBodies.item(0))
    face = body.faces.item(0)
    
    #find opposing face
    faceNormal = face.evaluator.getNormalAtPoint(face.pointOnFace)[1]
    oppFace = None

#find opposite side face    
    for face1 in face.body.faces:
        if faceNormal.isPerpendicularTo( face1.evaluator.getNormalAtPoint(face1.pointOnFace)[1]):
            continue
        if face1 == face:
            continue
        oppFace = face1
        break
    holeFeatures = face.body.parentComponent.features.holeFeatures  #surely - to be consistent, shouldn't holes be a feature of the component, not the rootComponent?
        
#    pointOnFace = face.nativeObject.pointOnFace
    pointOnFace = face.vertices.item(0).nativeObject.geometry
    offset = adsk.core.Vector3D.create(.1,.1,0)
    pointOnFace.translateBy(offset)
    
    edge1 = face.edges.item(0)
    edge2 = face.edges.item(1)
    
    holeInput = holeFeatures.createSimpleInput(holeDiam)
    holeInput.tipAngle = tipAngle
    holeInput.setPositionByPlaneAndOffsets(face, pointOnFace, edge1, holePosX, edge2, holePosY)
    holeInput.setOneSideToExtent(oppFace, True)
#    holeInput.setDistanceExtent(holeDepth)
    holeInput.creationOccurrence = embedded  #I would expect this to be needed, if not for generic case when?
    
    holeFeatures.add(holeInput)     
    
  except:
    if ui:
      ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) 

 If you can figure out what I'm doing wrong, I would really appreciate it.

 

Regards

Peter

I'm not an expert, but I know enough to be very, very dangerous.

Life long R&D Engineer (retired after 30+ years in Military Communications, Aerospace Robotics and Transport Automation).
0 Likes