Announcements
Attention for Customers without Multi-Factor Authentication or Single Sign-On - OTP Verification rolls out April 2025. Read all about it here.

Move and rotate sketch, from point to Selected Normal Edge

Anonymous

Move and rotate sketch, from point to Selected Normal Edge

Anonymous
Not applicable

Hello everyone, I'm creating a script to model WindMill blades aligning the airfoils by the %of the chord length.  Have created the script which read the data file and creates the airfoil sketch at the desired radial position (of the blade) by creating a sketch plane and spline.

The thing is I want to move the sketch by the "aerodynamic_center" to the selected (TwistAxis) edge and then rotate it by the (TwistAngle). I have tried different ways to do it, but it always rotates around the origin of the sketch.

Also, I have to check if the selected Edge (TwistAxis) is normal to the sketch plane.

 

import adsk.core, adsk.fusion, adsk.cam, traceback
from math import ceil,floor,radians
import os

# global set of event handlers to keep them referenced for the duration of the command
ui = None
app = adsk.core.Application.get()
if app:
    ui  = app.userInterface

handlers = []
product = app.activeProduct
design = adsk.fusion.Design.cast(product)

class Airfoil():
    def __init__(self, file):
        """

        :param name: 
        :param kwargs: 
        :raise Exception: 
        """
        self.coordinates = []
        self.camber_line = []
        self.__read_file(file)
        self.__get_camberline()
        self.aerodynamic_center = [0.25, 0.0]

    def __extremePoint(self):
        max_x = self.coordinates.index(max(self.coordinates,key=lambda pt: pt[0]))
        max_y = self.coordinates.index(max(self.coordinates,key=lambda pt: pt[1]))
        min_x = self.coordinates.index(min(self.coordinates,key=lambda pt: pt[0]))
        min_y = self.coordinates.index(min(self.coordinates,key=lambda pt: pt[1]))
        return [min_x, max_x], [min_y, max_y]

    def __get_camberline(self, points=50):
        n_points=len(self.coordinates)
        top = self.coordinates[:int(n_points/2)]
        bottom = self.coordinates[int(n_points/2):]
        #bottom[0]=top[-1]
        for i,point in enumerate(reversed(bottom)):
            mid_point_x = (point[0]+top[i][0])/2 
            mid_point_y = (point[1]+top[i][1])/2
            self.camber_line.append([mid_point_x,mid_point_y]) 

    def chord_size(self, chord):
        self.coordinates=[[p[0]*chord,p[1]*chord] for p in self.coordinates]
        self.camber_line=[[p[0]*chord,p[1]*chord] for p in self.camber_line]
        self.aerodynamic_center=[self.aerodynamic_center[0]*chord,self.aerodynamic_center[1]*chord]
    
    def set_aerodynamic_center(self, chord_percent=25):
        chord_position = chord_percent / 100
        self.aerodynamic_center = (chord_position,0)

    def __read_file(self, file):
        """
        :rtype : object
        :param name: 
        :return: :raise Exception: 
        """
        with open(file, 'r') as f:
            for line in f.readlines():
                line = line.strip(' \t')
                line = line.replace('\t', ' ')
                line = line.replace(',', ' ')
                p1 = line.find(" ")
                p2 = line.rfind(" ")
                x = float(line[0:p1])
                y = float(line[p2+1:])
                self.coordinates.append([x,y])
        self.coordinates[-1]=self.coordinates[0]

class CreateAirfoil():
    def Execute(self,Plane,Offset,Edge,Chord,TwistAxis,TwistAngle):
        dlg = ui.createFileDialog()
        dlg.title = 'Open DAT File'
        dlg.filter = 'Airfoil DAT files (*.dat);;Txt Files (*.txt);;All Files (*.*)'
        if dlg.showOpen() != adsk.core.DialogResults.DialogOK:
            return
        
        filename    = dlg.filename
        airfoil     = Airfoil(filename)
        airfoilName = filename.split("/")[-1].split(".")[0]
        
        if TwistAxis: airfoil.set_aerodynamic_center(TwistAxis)
        if Chord: airfoil.chord_size(Chord)

        root = design.rootComponent
        # Create a construction plane by offsetting the end face
        if Offset:
            planes             = root.constructionPlanes
            airfoilPlaneInput  = planes.createInput()
            offsetVal          = adsk.core.ValueInput.createByReal(Offset)
            airfoilPlaneInput.setByOffset(Plane, offsetVal)
            sketchPlane        = planes.add(airfoilPlaneInput)
            sketchPlane.name   = f'{airfoilName}_{Offset}'
        else:
            sketchPlane = Plane

        sketch             = root.sketches.add(sketchPlane)
        aerodynamic_center = adsk.core.Point3D.create(*airfoil.aerodynamic_center,0)
        points             = adsk.core.ObjectCollection.create()
        for p in airfoil.coordinates[1:-1]:
            x = p[0]
            y = -p[1]

            point = adsk.core.Point3D.create(x, y, 0.0)
            points.add(point)
            
        sketch.sketchCurves.sketchFittedSplines.add(points)
        sketch.sketchCurves.sketchLines.addByTwoPoints(points[0], points[-1])
        sketch.sketchPoints.add(aerodynamic_center)

        sketch.name=f'{airfoilName}_{Offset}'

class AirfoilCommandExecuteHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            command = args.firingEvent.sender
            inputs = command.commandInputs

            Plane       = inputs[0].selection(0).entity
            Offset      = inputs[1].value
            Edge        = inputs[2].selection(0).entity
            Chord       = inputs[3].value
            TwistAxis   = inputs[4].value
            TwistAngle  = inputs[5].value
           
            airfoil = CreateAirfoil()
            airfoil.Execute(Plane,Offset,Edge,Chord,TwistAxis,TwistAngle)
        except:
            if ui:
                ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

class AirfoilCommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            cmd = args.command
            onExecute = AirfoilCommandExecuteHandler()
            cmd.execute.add(onExecute)
            onDestroy = AirfoilCommandDestroyHandler()
            cmd.destroy.add(onDestroy)

            onValidateInput = AirfoilValidateInputHandler()
            cmd.validateInputs.add(onValidateInput)

            onInputChanged = AirfoilCommandInputChangedHandler()
            cmd.inputChanged.add(onInputChanged)

            # keep the handler referenced beyond this function
            handlers.append(onExecute)
            handlers.append(onDestroy)
            handlers.append(onValidateInput)
            handlers.append(onInputChanged)
            #define the inputs
            inputs = cmd.commandInputs
            i1 = inputs.addSelectionInput('BaseConstPlane', 'Reference Plane', 'Please select a construction plane')
            i1.addSelectionFilter(adsk.core.SelectionCommandInput.ConstructionPlanes)
            i1.addSelectionFilter(adsk.core.SelectionCommandInput.PlanarFaces)

            i2 = inputs.addDistanceValueCommandInput('AirfoilOffsetPlane', 'Airfoil distance from reference', adsk.core.ValueInput.createByReal(10))
            i2.isEnabled = False

            i3 = inputs.addSelectionInput('AirfoilAlignAxis', 'Center Edge', 'Please select a edge')
            i3.addSelectionFilter(adsk.core.SelectionCommandInput.Edges)
            i3.addSelectionFilter(adsk.core.SelectionCommandInput.ConstructionLines)

            i4 = inputs.addValueInput('AirfoilChord', 'ChordLength', '', adsk.core.ValueInput.createByReal(1))
            i4.minimumValue = 0
            i4.isMinimumValueInclusive = False

            i5 = inputs.addValueInput('TwistChord', "Twist Axis (% chord)", '', adsk.core.ValueInput.createByReal(25))
            i6 = inputs.addValueInput('Twist', 'TwistAngle', '', adsk.core.ValueInput.createByReal(0))
        except:
            if ui:
                ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

class AirfoilCommandDestroyHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            # when the command is done, terminate the script
            # this will release all globals which will remove all event handlers
            adsk.terminate()
        except:
            if ui:
                ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

class AirfoilValidateInputHandler(adsk.core.ValidateInputsEventHandler):
    def __init__(self):
        super().__init__()
       
    def notify(self, args):
        try:
            sels = ui.activeSelections
            if len(sels) == 2:
                args.areInputsValid = True
            else:
                args.areInputsValid = False
        except:
            if ui:
                ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

class AirfoilCommandInputChangedHandler(adsk.core.InputChangedEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            command = args.firingEvent.sender
            cmdInput = args.input
                
            if cmdInput.id == 'BaseConstPlane':
                inputs = cmdInput.commandInputs
                planeInput = inputs.itemById('BaseConstPlane')
                distanceInput = inputs.itemById('AirfoilOffsetPlane')
                
                if cmdInput.selectionCount > 0:
                    sel = cmdInput.selection(0)
                    selPt = sel.point
                    ent = sel.entity
                    plane = ent.geometry
                    
                    distanceInput.setManipulator(selPt, plane.normal)
                    distanceInput.isEnabled = True
                    distanceInput.isVisible = True
                else:
                    distanceInput.isEnabled = False
                    distanceInput.isVisible = False
        except:
            if ui:
                ui.messageBox(_('Input changed event failed: {}').format(traceback.format_exc()))

def run(context):
    try:
        title = 'Select Construction Plane'

        if not design:
            ui.messageBox('No active Fusion design', title)
            return

        commandDefinitions = ui.commandDefinitions

        # check the command exists or not
        cmdDef = commandDefinitions.itemById('BladeAirfoil')
        if not cmdDef:
            resourceDir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'Resources') # absolute resource file path is specified
            cmdDef = commandDefinitions.addButtonDefinition('BladeAirfoil',
                    'Airfoil Parameters',
                    'Creates airfoil spline on selected construction plane',
                    resourceDir)


        onCommandCreated = AirfoilCommandCreatedHandler()
        cmdDef.commandCreated.add(onCommandCreated)
        # keep the handler referenced beyond this function
        handlers.append(onCommandCreated)
        inputs = adsk.core.NamedValues.create()
        cmdDef.execute(inputs)

        # prevent this module from being terminate when the script returns, because we are waiting for event handlers to fire
        adsk.autoTerminate(False)

    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
0 Likes
Reply
Accepted solutions (1)
1,551 Views
4 Replies
Replies (4)

kandennti
Mentor
Mentor

Hi efirvida.

 

Could not run because there is no DAT file to test.

I created a sample to rotate the sketch instead.

#Fusion360API Python script
#Author-kantoku
#Description-Sketch Rotation test

import adsk.core, adsk.fusion, traceback
import math

def run(context):
    twistAngle = 30 #degree
    ui = None
    try:
        app  :adsk.core.Application = adsk.core.Application.get()
        ui   :adsk.core.UserInterface = app.userInterface
        des  :adsk.fusion.Design = app.activeProduct
        root :adsk.fusion.Component = des.rootComponent

        # Select Sketch
        msg :str = 'Select Sketch'
        selFiltter :str = 'Sketches'
        sel :adsk.core.Selection = selectEnt(ui, msg ,selFiltter)
        if not sel: return
        skt :adsk.fusion.Sketch = sel.entity

        # Select Egde
        msg = 'Select Egde(TwistAxis)'
        selFiltter = 'LinearEdges'
        sel :adsk.core.Selection = selectEnt(ui, msg ,selFiltter)
        if not sel: return
        twistAxis = sel.entity

        # Vertical check of sketch and edge
        plane = skt.referencePlane.geometry
        axis = twistAxis.geometry
        if not plane.isPerpendicularToLine(axis):
            msg = 'Please,Select the edge that is perpendicular to the sketch.'
            ui.messageBox(msg)
            return

        # skt.referencePlane - edge intersect Point
        origin = plane.intersectWithLine(axis.asInfiniteLine())

        # Get Sketch All Entitys
        sktEntitys = adsk.core.ObjectCollection.create()
        for c in skt.sketchCurves:
            sktEntitys.add(c) 
        for p in skt.sketchPoints:
            sktEntitys.add(p) 
        
        # Get Rotation Matrix3D
        mat3d = adsk.core.Matrix3D.create()
        angRad = math.radians(twistAngle)
        mat3d.setToRotation(angRad, axis.asInfiniteLine().direction, origin)

        # Execute Rotation
        skt.move(sktEntitys, mat3d)

        # finish
        app.activeViewport.refresh()
        ui.messageBox('Done')

    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

def selectEnt(
        ui :adsk.core.UserInterface,
        msg :str, 
        filtterStr :str) -> adsk.core.Selection :

    try:
        sel = ui.selectEntity(msg, filtterStr)
        return sel
    except:
        return None

Perhaps you should create a point that will be the center of rotation.

 

Testing with the attached data.

2.png

If you specify the red part for the sketch and the blue part for the edge,
I think you can confirm.

0 Likes

Anonymous
Not applicable

hi thanks for your help, but it didn't work for me, the rotation was in the wrong direction. In my post, I attach the ".dat" file as ".text" file because I can´t upload the forum didn't allow the upload of that files. I will try to explain with pictures what I need.

First I select the reference plane, and the centerline:

Annotation 2019-12-06 163658.jpg

Move the sketch by this point to the "aerodynamic_center" point to the selected edge, but stay on the "sketchPlane"

Annotation 2019-12-06 164141.jpg

something like:

 

Annotation 2019-12-06 164419.jpg

 

and then rotate it around that edge, like:

 

 

Annotation 2019-12-06 164938.jpg

 

taking into account that the Edge can be axis edge or shape Edge.

 

I update my code with your suggestion, and the results is:Annotation 2019-12-06 165617.jpg

Here is the code:

import adsk.core, adsk.fusion, adsk.cam, traceback
from math import ceil,floor,radians,pi
import os

# global set of event handlers to keep them referenced for the duration of the command
ui = None
app = adsk.core.Application.get()
if app:
    ui  = app.userInterface

handlers = []
product = app.activeProduct
design = adsk.fusion.Design.cast(product)

class Airfoil():
    def __init__(self, file):
        self.coordinates = []
        self.camber_line = []
        self.__read_file(file)
        self.__get_camberline()
        self.aerodynamic_center = [0.25, 0.0]

    def __extremePoint(self):
        max_x = self.coordinates.index(max(self.coordinates,key=lambda pt: pt[0]))
        max_y = self.coordinates.index(max(self.coordinates,key=lambda pt: pt[1]))
        min_x = self.coordinates.index(min(self.coordinates,key=lambda pt: pt[0]))
        min_y = self.coordinates.index(min(self.coordinates,key=lambda pt: pt[1]))
        return [min_x, max_x], [min_y, max_y]

    def __get_camberline(self, points=50):
        n_points=len(self.coordinates)
        top = self.coordinates[:int(n_points/2)]
        bottom = self.coordinates[int(n_points/2):]
        #bottom[0]=top[-1]
        for i,point in enumerate(reversed(bottom)):
            mid_point_x = (point[0]+top[i][0])/2 
            mid_point_y = (point[1]+top[i][1])/2
            self.camber_line.append([mid_point_x,mid_point_y]) 

    def chord_size(self, chord):
        self.coordinates=[[p[0]*chord,p[1]*chord] for p in self.coordinates]
        self.camber_line=[[p[0]*chord,p[1]*chord] for p in self.camber_line]
        self.aerodynamic_center=[self.aerodynamic_center[0]*chord,self.aerodynamic_center[1]*chord]
    
    def set_aerodynamic_center(self, chord_percent=25):
        chord_position = chord_percent / 100
        self.aerodynamic_center = (chord_position,0)

    def __read_file(self, file):
        with open(file, 'r') as f:
            for line in f.readlines():
                line = line.strip(' \t')
                line = line.replace('\t', ' ')
                line = line.replace(',', ' ')
                p1 = line.find(" ")
                p2 = line.rfind(" ")
                x = float(line[0:p1])
                y = float(line[p2+1:])
                self.coordinates.append([x,y])
        self.coordinates[-1]=self.coordinates[0]

class CreateAirfoil():
    def Execute(self,Plane,Offset,Edge,Chord,TwistAxis,TwistAngle):
        dlg = ui.createFileDialog()
        dlg.title = 'Open DAT File'
        dlg.filter = 'Airfoil DAT files (*.dat);;Txt Files (*.txt);;All Files (*.*)'
        if dlg.showOpen() != adsk.core.DialogResults.DialogOK:
            return
        
        filename    = dlg.filename
        airfoil     = Airfoil(filename)
        airfoilName = filename.split("/")[-1].split(".")[0]
        
        if TwistAxis: airfoil.set_aerodynamic_center(TwistAxis)
        if Chord: airfoil.chord_size(Chord)

        root = design.rootComponent

# Create a construction plane by offsetting the end face if Offset: planes = root.constructionPlanes airfoilPlaneInput = planes.createInput() offsetVal = adsk.core.ValueInput.createByReal(Offset) airfoilPlaneInput.setByOffset(Plane, offsetVal) sketchPlane = planes.add(airfoilPlaneInput) sketchPlane.name = f'{airfoilName}_{Offset}' else: sketchPlane = Plane sketch = root.sketches.add(sketchPlane) aerodynamic_center = adsk.core.Point3D.create(*airfoil.aerodynamic_center,0) points = adsk.core.ObjectCollection.create() for p in airfoil.coordinates[1:-1]: x = p[0] y = -p[1] point = adsk.core.Point3D.create(x, y, 0.0) points.add(point) sketch.sketchCurves.sketchFittedSplines.add(points) sketch.sketchCurves.sketchLines.addByTwoPoints(points[0], points[-1]) sketch.sketchPoints.add(aerodynamic_center) # skt.referencePlane - edge intersect Point axis = Edge.geometry plane = sketchPlane.geometry angRad = radians(TwistAngle) if axis.classType() == 'adsk::core::Line3D': origin = plane.intersectWithLine(axis.asInfiniteLine()) axis = axis.asInfiniteLine().direction else: origin = plane.intersectWithLine(axis) axis = axis.direction # Get Sketch All Entitys sktEntitys = adsk.core.ObjectCollection.create() for c in sketch.sketchCurves: sktEntitys.add(c) for p in sketch.sketchPoints: sktEntitys.add(p) # Execute Rotation mat3d = adsk.core.Matrix3D.create() mat3d.setToRotation(angRad, axis, origin) sketch.move(sktEntitys, mat3d) sketch.name=f'{airfoilName}_{Offset}' class AirfoilCommandExecuteHandler(adsk.core.CommandEventHandler): def __init__(self): super().__init__() def notify(self, args): try: command = args.firingEvent.sender inputs = command.commandInputs Plane = inputs[0].selection(0).entity Offset = inputs[1].value Edge = inputs[2].selection(0).entity Chord = inputs[3].value TwistAxis = inputs[4].value TwistAngle = inputs[5].value airfoil = CreateAirfoil() airfoil.Execute(Plane,Offset,Edge,Chord,TwistAxis,TwistAngle) except: if ui: ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) class AirfoilCommandCreatedHandler(adsk.core.CommandCreatedEventHandler): def __init__(self): super().__init__() def notify(self, args): try: cmd = args.command onExecute = AirfoilCommandExecuteHandler() cmd.execute.add(onExecute) onDestroy = AirfoilCommandDestroyHandler() cmd.destroy.add(onDestroy) onValidateInput = AirfoilValidateInputHandler() cmd.validateInputs.add(onValidateInput) onInputChanged = AirfoilCommandInputChangedHandler() cmd.inputChanged.add(onInputChanged) #onSelectionChanged = AirfoilSelectionEventHandler() #cmd.inputChanged.add(onSelectionChanged) # keep the handler referenced beyond this function handlers.append(onExecute) handlers.append(onDestroy) #handlers.append(onValidateInput) handlers.append(onInputChanged) #handlers.append(onSelectionChanged) #define the inputs inputs = cmd.commandInputs i1 = inputs.addSelectionInput('BaseConstPlane', 'Reference Plane', 'Please select a construction plane') i1.addSelectionFilter(adsk.core.SelectionCommandInput.ConstructionPlanes) i1.addSelectionFilter(adsk.core.SelectionCommandInput.PlanarFaces) i2 = inputs.addDistanceValueCommandInput('AirfoilOffsetPlane', 'Airfoil distance from reference', adsk.core.ValueInput.createByReal(10)) i2.isEnabled = False i3 = inputs.addSelectionInput('AirfoilAlignAxis', 'Center Edge', 'Please select a edge') i3.addSelectionFilter("LinearEdges") i3.addSelectionFilter("ConstructionLines") i4 = inputs.addValueInput('AirfoilChord', 'ChordLength', '', adsk.core.ValueInput.createByReal(1)) i4.minimumValue = 0 i4.isMinimumValueInclusive = False i5 = inputs.addValueInput('TwistChord', "Twist Axis (% chord)", '', adsk.core.ValueInput.createByReal(25)) i6 = inputs.addValueInput('Twist', 'TwistAngle', '', adsk.core.ValueInput.createByReal(0)) except: if ui: ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) class AirfoilCommandDestroyHandler(adsk.core.CommandEventHandler): def __init__(self): super().__init__() def notify(self, args): try: # when the command is done, terminate the script # this will release all globals which will remove all event handlers adsk.terminate() except: if ui: ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) class AirfoilValidateInputHandler(adsk.core.ValidateInputsEventHandler): def __init__(self): super().__init__() def notify(self, args): try: sels = ui.activeSelections if len(sels) == 2: args.areInputsValid = True else: args.areInputsValid = False except: if ui: ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) class AirfoilCommandInputChangedHandler(adsk.core.InputChangedEventHandler): def __init__(self): super().__init__() def notify(self, args): try: command = args.firingEvent.sender cmdInput = args.input inputs = cmdInput.commandInputs if cmdInput.id == 'BaseConstPlane': planeInput = inputs.itemById('BaseConstPlane') distanceInput = inputs.itemById('AirfoilOffsetPlane') if cmdInput.selectionCount > 0: sel = cmdInput.selection(0) selPt = sel.point ent = sel.entity plane = ent.geometry distanceInput.setManipulator(selPt, plane.normal) distanceInput.isEnabled = True distanceInput.isVisible = True else: distanceInput.isEnabled = False distanceInput.isVisible = False except: if ui: ui.messageBox(_('Input changed event failed: {}').format(traceback.format_exc())) class AirfoilSelectionEventHandler(adsk.core.InputChangedEventHandler): def __init__(self): super().__init__() def notify(self, args): try: eventArgs = adsk.core.SelectionEventArgs.cast(args) inputs = eventArgs.firingEvent.sender.commandInputs plane = inputs.itemById('BaseConstPlane').selection(0).entity axis = inputs.itemById('AirfoilAlignAxis').selection(0).entity if axis.geometry.classType() == 'adsk::core::Line3D' and \ not plane.geometry.isPerpendicularToLine(axis.geometry): eventArgs.areInputsValid = False msg = 'Please,Select the edge that is perpendicular to the plane.' ui.messageBox(msg) else: eventArgs.areInputsValid = True except: if ui: ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) def run(context): try: title = 'Select Construction Plane' if not design: ui.messageBox('No active Fusion design', title) return commandDefinitions = ui.commandDefinitions # check the command exists or not cmdDef = commandDefinitions.itemById('BladeAirfoil') if not cmdDef: resourceDir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'Resources') # absolute resource file path is specified cmdDef = commandDefinitions.addButtonDefinition('BladeAirfoil', 'Airfoil Parameters', 'Creates airfoil spline on selected construction plane', resourceDir) onCommandCreated = AirfoilCommandCreatedHandler() cmdDef.commandCreated.add(onCommandCreated) # keep the handler referenced beyond this function handlers.append(onCommandCreated) inputs = adsk.core.NamedValues.create() cmdDef.execute(inputs) # prevent this module from being terminate when the script returns, because we are waiting for event handlers to fire adsk.autoTerminate(False) except: if ui: ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

and the .dat file:

 

1.000000   0.000000
0.996203   0.000487
0.985190   0.002373
0.967844   0.005960
0.945073   0.011024
0.917488   0.017033
0.885293   0.023458
0.848455   0.030280
0.807470   0.037766
0.763042   0.045974
0.715952   0.054872
0.667064   0.064353
0.617331   0.074214
0.567830   0.084095
0.519832   0.093268
0.474243   0.099392
0.428461   0.101760
0.382612   0.101840
0.337260   0.100070
0.292970   0.096703
0.250247   0.091908
0.209576   0.085851
0.171409   0.078687
0.136174   0.070580
0.104263   0.061697
0.076035   0.052224
0.051823   0.042352
0.031910   0.032299
0.016590   0.022290
0.006026   0.012615
0.000658   0.003723
0.000204   0.001942
0.000000  -0.000020
0.000213  -0.001794
0.001045  -0.003477
0.001208  -0.003724
0.002398  -0.005266
0.009313  -0.011499
0.023230  -0.020399
0.042320  -0.030269
0.065877  -0.040821
0.093426  -0.051923
0.124111  -0.063082
0.157653  -0.073730
0.193738  -0.083567
0.231914  -0.092442
0.271438  -0.099905
0.311968  -0.105281
0.353370  -0.108181
0.395329  -0.108011
0.438273  -0.104552
0.481920  -0.097347
0.527928  -0.086571
0.576211  -0.073979
0.626092  -0.060644
0.676744  -0.047441
0.727211  -0.035100
0.776432  -0.024204
0.823285  -0.015163
0.866630  -0.008204
0.905365  -0.003363
0.938474  -0.000487
0.965086   0.000743
0.984478   0.000775
0.996141   0.000290
1.000000   0.000000 

Thanks again for your help.

 

 

 

 

0 Likes

kandennti
Mentor
Mentor
Accepted solution

I didn't notice the attached file.
If it is the same as the Japanese forum, I think that it can be attached as a ZIP file.


I tried and corrected a lot.
Please check the attached file as it includes minor modifications.

The most significant modification was the CreateAirfoil class.

class CreateAirfoil():
    def Execute(self,Plane,Offset,Edge,Chord,TwistAxis,TwistAngle):
        
        ・・・
        
        sketch.isComputeDeferred = True
        sketch.sketchCurves.sketchFittedSplines.add(points)
        sketch.sketchCurves.sketchLines.addByTwoPoints(points[0], points[-1])
        sktCenterPnt =  sketch.sketchPoints.add(aerodynamic_center)

        # skt.referencePlane - edge intersect Point
        axis = Edge.geometry
        plane = sketchPlane.geometry 

        if axis.classType() == 'adsk::core::Line3D':
            origin = plane.intersectWithLine(axis.asInfiniteLine())
        else:
            origin = plane.intersectWithLine(axis)
        
        # Get Sketch All Entitys
        sktEntitys = adsk.core.ObjectCollection.create()
        [sktEntitys.add(c) for c in sketch.sketchCurves]
        [sktEntitys.add(p) for p in sketch.sketchPoints]

        # get Rotatione matrix
        angRad = radians(TwistAngle)
        rotationAxis = adsk.core.Vector3D.create(0,0,1)
        rotationCenter = sktCenterPnt.geometry.copy()
        rotationMat = adsk.core.Matrix3D.create()
        rotationMat.setToRotation(angRad, rotationAxis, rotationCenter)

        # get Move matrix
        ori = origin.copy()
        sktmat = sketch.transform
        sktmat.invert()
        ori.transformBy(sktmat)
        centerGeo = sktCenterPnt.geometry
        vecMove = centerGeo.vectorTo(ori)
        moveMat = adsk.core.Matrix3D.create()
        moveMat.translation = vecMove

        # Execute Rotatione&Move
        mat3d = rotationMat.copy()
        mat3d.transformBy(moveMat)
        sketch.move(sktEntitys, mat3d)
        sketch.isComputeDeferred = False

        sketch.name=f'{airfoilName}_{Offset}'

"Sketch.isComputeDeferred = True" to reduce processing time using.

 

You may feel that the direction of rotation is reversed.
I think that is due to the direction of viewing.
I believe I created it to rotate in the right direction.

 

In addition, we modified the AirfoilValidateInputHandler class and set it to work.

However, when selecting the first element ('BaseConstPlane' or 'AirfoilAlignAxis') after starting the script, the OK button was not grayed out.
(The ’command.validateInputs’ is not called for the first selection)
I didn't know why.

1.png

In other situations, it should be working.

1 Like

Anonymous
Not applicable

Thanks a lot, it works perfectly

0 Likes