Disable unit autofill?

Disable unit autofill?

Anonymous
Not applicable
2,555 Views
18 Replies
Message 1 of 19

Disable unit autofill?

Anonymous
Not applicable

Someone just told me that the units autofill too fast and it is hard to change numbers when you press backlash and the unit reappears, I totally agree on this and would like to fix this in my addin's. 

 

Is there a way to disable the autofill of the unit or making it slower when using unit-manager? Or maybe even make the unit hidden? 

0 Likes
Accepted solutions (1)
2,556 Views
18 Replies
Replies (18)
Message 2 of 19

marshaltu
Autodesk
Autodesk

Hello,

 

It would be good if you can give some snapshots or screencast to demostrate your issue. I have no idea what unit auto fill you meant.

 

Thanks,

Marshal



Marshal Tu
Fusion Developer
>
0 Likes
Message 3 of 19

Anonymous
Not applicable

I mean something like the following screencast. The addin is coded with c++, it's using the unit manager and validation of the values with validateInput. Maybe the validating has something to do with this problem? 

 

 

 

 

0 Likes
Message 4 of 19

Anonymous
Not applicable

 

 

 

0 Likes
Message 5 of 19

marshaltu
Autodesk
Autodesk

Hello,

 

Unfortunately I cannot reproduce the issue you demonstrated in either Windows or MAC. Please refer to my screencast.

 

http://autode.sk/2ov065F

 

Could you please try other commands( e.g. extrude, spur gear generated by API sample) and see if there is same behaviour? If yes, we have to figure out what's difference between our environments. If not, it would be specific to your addin. Please share your addin to me for analysis.

 

Thanks,

Marshal



Marshal Tu
Fusion Developer
>
0 Likes
Message 6 of 19

Anonymous
Not applicable

There is exactly the same problem in the spur gear sample, I guess the autofill happens if you validate the number input and a valid number is entered. Check the root fillet radius in the c++ spur gear addin sample. 

 

 

0 Likes
Message 7 of 19

marshaltu
Autodesk
Autodesk

Hello,

 

The root cause was that we called "_rootFilletRad.value"(marked as red) in validate inputs event handler to trigger the command input was updated forcely. It worked well if I commented out the line.

 

Thanks,

Marshal

 

class GearCommandValidateInputsHandler(adsk.core.ValidateInputsEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            eventArgs = adsk.core.ValidateInputsEventArgs.cast(args)
            
            _errMessage.text = ''

            # Verify that at lesat 4 teath are specified.
            if not _numTeeth.value.isdigit():
                _errMessage.text = 'The number of teeth must be a whole number.'
                eventArgs.areInputsValid = False
                return
            else:    
                numTeeth = int(_numTeeth.value)
            
            if numTeeth < 4:
                _errMessage.text = 'The number of teeth must be 4 or more.'
                eventArgs.areInputsValid = False
                return
                
            # Calculate some of the gear sizes to use in validation.
            if _standard.selectedItem.name == 'English':
                result = getCommandInputValue(_diaPitch, '')
                if result[0] == False:
                    eventArgs.areInputsValid = False
                    return
                else:
                    diaPitch = result[1]
            elif _standard.selectedItem.name == 'Metric':
                result = getCommandInputValue(_module, '')
                if result[0] == False:
                    eventArgs.areInputsValid = False
                    return
                else:
                    diaPitch = 25.4 / result[1]

            diametralPitch = diaPitch / 2.54
            pitchDia = numTeeth / diametralPitch
            
            if (diametralPitch < (20 *(math.pi/180))-0.000001):
                dedendum = 1.157 / diametralPitch
            else:
                circularPitch = math.pi / diametralPitch
                if circularPitch >= 20:
                    dedendum = 1.25 / diametralPitch
                else:
                    dedendum = (1.2 / diametralPitch) + (.002 * 2.54)                

            rootDia = pitchDia - (2 * dedendum)        
                    
            if _pressureAngle.selectedItem.name == 'Custom':
                pressureAngle = _pressureAngleCustom.value
            else:
                if _pressureAngle.selectedItem.name == '14.5 deg':
                    pressureAngle = 14.5 * (math.pi/180)
                elif _pressureAngle.selectedItem.name == '20 deg':
                    pressureAngle = 20.0 * (math.pi/180)
                elif _pressureAngle.selectedItem.name == '25 deg':
                    pressureAngle = 25.0 * (math.pi/180)
            baseCircleDia = pitchDia * math.cos(pressureAngle)
            baseCircleCircumference = 2 * math.pi * (baseCircleDia / 2) 

            des = adsk.fusion.Design.cast(_app.activeProduct)

            result = getCommandInputValue(_holeDiam, _units)
            if result[0] == False:
                eventArgs.areInputsValid = False
                return
            else:
                holeDiam = result[1]
                           
            if holeDiam >= (rootDia - 0.01):
                _errMessage.text = 'The center hole diameter is too large.  It must be less than ' + des.unitsManager.formatInternalValue(rootDia - 0.01, _units, True)
                eventArgs.areInputsValid = False
                return

            toothThickness = baseCircleCircumference / (numTeeth * 2)
            if _rootFilletRad.value > toothThickness * .4:
                _errMessage.text = 'The root fillet radius is too large.  It must be less than ' + des.unitsManager.formatInternalValue(toothThickness * .4, _units, True)
                eventArgs.areInputsValid = False
                return
        except:
            if _ui:
                _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))


Marshal Tu
Fusion Developer
>
0 Likes
Message 8 of 19

Anonymous
Not applicable

Yes but that would also remove the validation of the value? The line is there for a reason.  
How can I fix this without removing the check for the right values? If, for example, a gear is created with the wrong values it will not work. Or a hole is too large in the middle of the gear, it will remove the whole body. 

0 Likes
Message 9 of 19

marshaltu
Autodesk
Autodesk
Accepted solution

Hello,

 

Good news are there was already a solution in the sample. It seemed that we missed the command input. Please refer to the codes marked as red for how to get the "value" from command input without forcely updating the input.

 

Thanks,

Marshal

 

class GearCommandValidateInputsHandler(adsk.core.ValidateInputsEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            eventArgs = adsk.core.ValidateInputsEventArgs.cast(args)
            
            _errMessage.text = ''

            # Verify that at lesat 4 teath are specified.
            if not _numTeeth.value.isdigit():
                _errMessage.text = 'The number of teeth must be a whole number.'
                eventArgs.areInputsValid = False
                return
            else:    
                numTeeth = int(_numTeeth.value)
            
            if numTeeth < 4:
                _errMessage.text = 'The number of teeth must be 4 or more.'
                eventArgs.areInputsValid = False
                return
                
            # Calculate some of the gear sizes to use in validation.
            if _standard.selectedItem.name == 'English':
                result = getCommandInputValue(_diaPitch, '')
                if result[0] == False:
                    eventArgs.areInputsValid = False
                    return
                else:
                    diaPitch = result[1]
            elif _standard.selectedItem.name == 'Metric':
                result = getCommandInputValue(_module, '')
                if result[0] == False:
                    eventArgs.areInputsValid = False
                    return
                else:
                    diaPitch = 25.4 / result[1]

            diametralPitch = diaPitch / 2.54
            pitchDia = numTeeth / diametralPitch
            
            if (diametralPitch < (20 *(math.pi/180))-0.000001):
                dedendum = 1.157 / diametralPitch
            else:
                circularPitch = math.pi / diametralPitch
                if circularPitch >= 20:
                    dedendum = 1.25 / diametralPitch
                else:
                    dedendum = (1.2 / diametralPitch) + (.002 * 2.54)                

            rootDia = pitchDia - (2 * dedendum)        
                    
            if _pressureAngle.selectedItem.name == 'Custom':
                pressureAngle = _pressureAngleCustom.value
            else:
                if _pressureAngle.selectedItem.name == '14.5 deg':
                    pressureAngle = 14.5 * (math.pi/180)
                elif _pressureAngle.selectedItem.name == '20 deg':
                    pressureAngle = 20.0 * (math.pi/180)
                elif _pressureAngle.selectedItem.name == '25 deg':
                    pressureAngle = 25.0 * (math.pi/180)
            baseCircleDia = pitchDia * math.cos(pressureAngle)
            baseCircleCircumference = 2 * math.pi * (baseCircleDia / 2) 

            des = adsk.fusion.Design.cast(_app.activeProduct)

            result = getCommandInputValue(_holeDiam, _units)
            if result[0] == False:
                eventArgs.areInputsValid = False
                return
            else:
                holeDiam = result[1]
                           
            if holeDiam >= (rootDia - 0.01):
                _errMessage.text = 'The center hole diameter is too large.  It must be less than ' + des.unitsManager.formatInternalValue(rootDia - 0.01, _units, True)
                eventArgs.areInputsValid = False
                return

            toothThickness = baseCircleCircumference / (numTeeth * 2)
            result = getCommandInputValue(_rootFilletRad, _units)
            if result[0] == False:
                eventArgs.areInputsValid = False
                return 
            else:
                if result[1] > toothThickness * .4:
                    _errMessage.text = 'The root fillet radius is too large.  It must be less than ' + des.unitsManager.formatInternalValue(toothThickness * .4, _units, True)
                    eventArgs.areInputsValid = False
                    return
        except:
            if _ui:
                _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))


Marshal Tu
Fusion Developer
>
0 Likes
Message 10 of 19

Anonymous
Not applicable

Thanks, I'll try this with my Addin.

In the c++ sketch it says that this will be added the ValueCommandInput object to make things easier, any idea when this will happen? I would need to rewrite everything twice if I start changing things.

 

0 Likes
Message 11 of 19

Anonymous
Not applicable

I see a double helical gear - is that what you are trying to do with your addin? If so be aware of my helical gear generator and I'll share that I'm nearing delivering version 2.0 which will add a lot of features (including directly creating double helix gears).

0 Likes
Message 12 of 19

Anonymous
Not applicable

Yeah, I am aware of that one. I wrote this a long time ago (about the same time as you released your first version) but never published it because you got there first. 🙂

Now I tried my Addin again and it seemed to have some broken bits with the updates so I decided to fix these. But I was thinking I may share it(if fusion shop will take it) since it did have some functionality the Helical Gear Generator didn't seem to have, like the herringbone gears, choosing between simulating(undercut compensation and profile shift) and calculating the tooth profile, diametral pitch and circular pitch instead of module, different types of profiles for the inner hole and so on.

Mine seems a bit slower though because it generates the whole profile in the sketch instead of multiplying 3D shapes. I also wrote a (hopefully proper)bevel gear generator around the same time that approximates the tooth shape, maybe I should fix that too. 

 

bevel.png

Message 13 of 19

Anonymous
Not applicable

And/or maybe we should work together 😛 mines written in python - I would really appreciate having a second brain on this stuff. I would be happy to share my Alpha code with you (no obligation), it's quite rough at the moment (the code that is... and the preview experience), and I have a lot of work to do on improving performance, but it is otherwise fully functional.

 

The code under the hood in my v2.0 can also compute shifted profiles but as profile shifting only makes sense when you are dealing with 2 gears I'm not planning to expose that ability (yet). In addition to what I show below the code is also capable of making some crazy things and it can sensibly generate involute profiles up to 89 deg pressure angles (which are totally useless as gears obviously)

 

I've also written the code to generate proper spherical involutes for bevel gears but I haven't taken it to fully generating a gear - largely because along the way I learned that without crowing bevel gears (esp. 3D printed ones) are not likely to operate smoothly and that just seems like a real pain to make happen in the fusion API.

 

Internal double helical gear with capping and point reliefInternal double helical gear with capping and point relief

 

 

 

0 Likes
Message 14 of 19

Anonymous
Not applicable

Working together would be great but unfortunately, I have written everything in C++. And the code is a mess. 🙂

 I would like to start working on this again but I also have a lot of other projects at the moment, and I need to find more actual work to make a living.

I actually also made a gear generator with inside gears. I love the fact that you added capping and point relief, it makes it so much cooler. And I like the wavy patterns, 3D printing those would be pretty fun. DDS modeling would also be interesting. I have it on my list of things to play around with, just too bad it would be pretty slow in Fusion360.

Heres some gears with my Addins:

 

bevel2.png internal gear.pngherrinboneSimulated.png

0 Likes
Message 15 of 19

Anonymous
Not applicable

Double post so I removed the text, sorry for that. We need a remove button to the forums. 

0 Likes
Message 16 of 19

Anonymous
Not applicable

Very cool! Can you generate bevel gears with a mesh at angles other than 90deg? In any case you should release those if you are up to keeping them working 😉

 

I'm not sure it's possible to write a substantial fusion add-in with code that isn't a mess, but I've done what I can to abstract out the event object construct and the terribly inconsistent and verbose UI element creation and interaction as well as elegantly maintaining UI state between invocations, etc.

 

I think it would be great if you were willing to collaborate and idea share even if you didn't want to work on the same codebase. I chose python because it's easier for others to understand the code and I like dynamic languages for some things, and lets face it the language the add-in is written in has no impact on performance - the slow part is the Fusion API by a huge margin.

 

Anyway, I'm still willing to share my code with you if you are curios. I'm curious how you are giving your helical gears their twist, it's not obvious from the timeline in your screencast above. In my v1 add-in I'm using loft (which crashes fusion if you run my add-in with capture history off) and in v2 i'm using the new sweep with a twist. Sweep is comparably very fast when you are using a complete gear profile - the "hard" part is computing the sweep "twist" value from a helix angle.

 

Have you tried to see if gears your addin generates and the ones mine generate properly mesh with eachother? So far I've not had any other interpretation of helical gears to compare against. I know there is another helical gear add-in but it doesn't generate valid helix profiles - the profile it generates has an unintentionally varying helix angle over the length of the gear.

0 Likes
Message 17 of 19

Anonymous
Not applicable

I wouldn't mind sharing code, but I would need to get used to Python again. It is a while since I coded with it and I don't really feel at home with the language. 

 

For the Bevel gears, yeah you can choose the angle. It is using tredgold approximation since this is how it seems to be done everywhere, but it could be made better 🙂
Also, I never had time to figure out the proper way to calculate a spiral angle for spiral bevel gears. I haven't touched the code in more than a year and it seems to be crashing fusion with some gear sizes. I would need to fix this if I will publish it.

 

In the helical gear generator, I am making a sweep with 2 rails, one in the middle going along the axis. The other is a spline that is calculated to go along with the rotation, positioned on the pitch diameter.
First I am making one tooth in sketch mode, then rotating and copying it with matrix multiplication. So I draw the spur gear in sketch mode and then make the sweep. The biggest problem I have encountered here is the sketch workspace being so slow. 

The gears in my generator seem to pretty much match with your "radial system". The image is your gear on the top and 2 of mine in the "inside of it", I rotated them to place by guessing the angle so they don't exactly match in this image.

And sorry for the bad quality, my graphics card broke last week so the rendering is bad 🙂 

 

radial.png

0 Likes
Message 18 of 19

Anonymous
Not applicable

Try using the new twist sweep instead of the guide rail sweep, it's a lot more accurate and a lot faster

 

Here's my "twist calculator"

 

class TwistCalculator(object):

  def __init__(self, helix_angle, pitch_radius):
    self._c = math.tan(math.pi/2 - abs(helix_angle)) * pitch_radius if helix_angle != 0 else None
    if helix_angle < 0:
      self._c *= -1

  def reverse(self):
    self._c *= -1

  def twist_over_displacement(self, displacement):
    return displacement / self._c if self._c else 0

And then doing the sweep looks something like this

sweeps = self._component.features.sweepFeatures
si = sweeps.createInput(profile, self._path, adsk.fusion.FeatureOperations.NewBodyFeatureOperation)  
si.twistAngle = adsk.core.ValueInput.createByReal(self._twist_calculator.twist_over_displacement(self._length))
sweep = sweeps.add(si)

 

 

Bevel Gears...

I'll have to look into tredgold approximation - I'm strait up computing the involute on a spherical surface. Then it's trivial to project (actually ray-cast from origin) that involute onto a plane so fusion has a profile to work with. I used this source for the spherical involute math if you're curios http://thermalprocessing.com/media/2017/201703/0317-Forging.pdf I really hate "math papers" - i swear they say stuff in ways intended to make understanding hard. It's not actually that complicated of a problem to calculate a spherical involute but everything I found on the subject sure made it hard to understand!

 

 

 

 

Message 19 of 19

marshaltu
Autodesk
Autodesk

Hello,

 

Unfortunately that wasn't tracked in our internal system yet. I logged it as UP-38239 to track it now. The issue need be prioritized with other tasks. So I cannot give estimation right now.

 

Thanks,

Marshal



Marshal Tu
Fusion Developer
>
0 Likes