Skip to content

Instantly share code, notes, and snippets.

@marcosscriven
Forked from JesusFreke/README.md
Created August 5, 2020 13:13
Show Gist options
  • Save marcosscriven/009febeff02af187fcca78dcf5292fb6 to your computer and use it in GitHub Desktop.
Save marcosscriven/009febeff02af187fcca78dcf5292fb6 to your computer and use it in GitHub Desktop.
Fusion 360 API Example: wrap sketch around surface

This is an example of using SurfaceEvaluator.getModelCurveFromParametricCurve in order to do a true wrap (not just a projection) of a 2D sketch onto a curved surface. This can be used, for example, to wrap text around a cylinder or even a sphere. It should be possible to map a sketch onto most any surface.

# Copyright 2018, Ben Gruver
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation and/or
# other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors
# may be used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import adsk.core
import adsk.fusion
import math
import traceback
app = adsk.core.Application.get()
root = app.activeProduct.rootComponent
def create_component(parent_component, *bodies, name=None):
"""Create a new component from temporary brep bodies"""
new_occurrence = parent_component.occurrences.addNewComponent(adsk.core.Matrix3D.create())
if name is not None:
new_occurrence.component.name = name
base_feature = new_occurrence.component.features.baseFeatures.add()
base_feature.startEdit()
for body in bodies:
new_occurrence.component.bRepBodies.add(body, base_feature)
base_feature.finishEdit()
return new_occurrence
def collection_of(collection):
object_collection = adsk.core.ObjectCollection.create()
for obj in collection:
object_collection.add(obj)
return object_collection
def convert_vector(vector):
return adsk.core.Vector2D.create(vector.x, vector.y)
def convert_point(point):
return adsk.core.Point2D.create(point.y, point.x)
def convert_curve(curve, transform):
result = None
if isinstance(curve, adsk.core.Arc3D):
# TODO: need to take referenceVector into account, in order to get the proper rotation of the start/end
# points of the rotated arc
result = adsk.core.Arc2D.createByCenter(
convert_point(curve.center),
curve.radius,
curve.startAngle,
curve.endAngle,
False)
elif isinstance(curve, adsk.core.Circle3D):
result = adsk.core.Circle2D.createByCenter(
convert_point(curve.center),
curve.radius)
elif isinstance(curve, adsk.core.Ellipse3D):
result = adsk.core.Ellipse2D.create(
convert_point(curve.center),
convert_vector(curve.majorAxis),
curve.majorRadius,
curve.minorRadius)
elif isinstance(curve, adsk.core.EllipticalArc3D):
result = adsk.core.EllipticalArc2D.create(
convert_point(curve.center),
convert_vector(curve.majorAxis),
curve.majorRadius,
curve.minorRadius,
curve.startAngle,
curve.endAngle)
elif isinstance(curve, adsk.core.Line3D):
result = adsk.core.Line2D.create(
convert_point(curve.startPoint), convert_point(curve.endPoint))
elif isinstance(curve, adsk.core.NurbsCurve3D):
control_points = []
for control_point in curve.controlPoints:
control_points.append(convert_point(control_point))
if curve.isRational:
result = adsk.core.NurbsCurve2D.createRational(
control_points,
curve.degree,
curve.knots,
curve.getData()[4],
curve.isPeriodic)
else:
result = adsk.core.NurbsCurve2D.createNonRational(
control_points,
curve.degree,
curve.knots,
curve.isPeriodic)
elif isinstance(curve, adsk.core.InfiniteLine3D):
raise ValueError("Infinite lines can't be converted to a 2D curve")
if result is None:
raise ValueError("Unknown curve type: %s", type(curve).__name__)
result.transformBy(transform)
return result
def split_face(faces, curves):
split_input = root.features.splitFaceFeatures.createInput(
collection_of(faces), collection_of(curves), False)
split_input.setClosestPointSplitType()
feature = root.features.splitFaceFeatures.add(split_input)
feature_faces = []
# the face references on the feature object become invalid/buggy for some reason
# so we just mark the relevant faces and then use Design.findAttributes to get them
# again for the next split
for face in feature.faces:
face.attributes.add("wrap", "face_to_wrap", "true")
return feature_faces
def wrap_sketch_and_split(sketch, face, transform):
brep = adsk.fusion.TemporaryBRepManager.get()
split_body = face.body
face.attributes.add("wrap", "face_to_wrap", "true")
model_curves = []
for curve in sketch.sketchCurves:
model_curves.extend(face.evaluator.getModelCurveFromParametricCurve(
convert_curve(curve.worldGeometry, transform)))
wire, _ = brep.createWireFromCurves(model_curves)
wire_occurrence = create_component(root, wire, name="wire")
wrapped_sketch = root.sketches.add(root.xYConstructionPlane)
wrapped_sketch.name = "wrapped sketch"
count = 0
for body in wire_occurrence.bRepBodies:
for wire in body.wires:
count += 1
edges = []
print("processing wire %d/%d" % (count, body.wires.count))
for edge in wire.edges:
edges.extend(list(wrapped_sketch.include(edge)))
faces_to_split = []
for attr in app.activeProduct.findAttributes("wrap", "face_to_wrap"):
faces_to_split.append(attr.parent)
for face in split_face(faces_to_split, edges):
if face not in faces_to_split:
faces_to_split.append(face)
for attr in app.activeProduct.findAttributes("wrap", "face_to_wrap"):
attr.deleteMe()
wire_occurrence.isLightBulbOn = False
wrapped_sketch.isLightBulbOn = False
def setup_document(document_name):
preview_doc = None # type: adsk.fusion.FusionDocument
saved_camera = None
for document in app.documents:
if document.name == document_name:
preview_doc = document
break
if preview_doc is not None:
preview_doc.activate()
saved_camera = app.activeViewport.camera
preview_doc.close(False)
preview_doc = app.documents.add(adsk.core.DocumentTypes.FusionDesignDocumentType)
preview_doc.name = document_name
preview_doc.activate()
if saved_camera is not None:
is_smooth_transition_bak = saved_camera.isSmoothTransition
saved_camera.isSmoothTransition = False
app.activeViewport.camera = saved_camera
saved_camera.isSmoothTransition = is_smooth_transition_bak
app.activeViewport.camera = saved_camera
def sphere(radius, *, name="Sphere") -> adsk.fusion.Occurrence:
brep = adsk.fusion.TemporaryBRepManager.get()
sphere_body = brep.createSphere(adsk.core.Point3D.create(0, 0, 0), radius)
occurrence = create_component(root, sphere_body, name=name)
return occurrence
def cylinder(height, radius, radius2=None, *, name="Cylinder") -> adsk.fusion.Occurrence:
brep = adsk.fusion.TemporaryBRepManager.get()
cylinder_body = brep.createCylinderOrCone(
adsk.core.Point3D.create(0, 0, 0),
radius,
adsk.core.Point3D.create(0, 0, height),
radius if radius2 is None else radius2
)
return create_component(root, cylinder_body, name=name)
def run(context):
try:
setup_document("wrap_example")
global app, root
app = adsk.core.Application.get()
root = app.activeProduct.rootComponent # type: adsk.fusion.Component
sketch = root.sketches.add(root.xYConstructionPlane)
text_input = sketch.sketchTexts.createInput("abcd", 2, adsk.core.Point3D.create(0, 0, 0))
text = sketch.sketchTexts.add(text_input)
text.explode()
obj = cylinder(2, 2)
faces = obj.component.findBRepUsingPoint(
adsk.core.Point3D.create(0, 2, 1),
adsk.fusion.BRepEntityTypes.BRepFaceEntityType)
transform = adsk.core.Matrix2D.create()
transform.setCell(0, 0, .5)
transform.setCell(1, 1, .5)
transform.setCell(0, 2, -.3)
transform.setCell(1, 2, -1)
wrap_sketch_and_split(sketch, faces[0], transform)
obj2 = sphere(2)
wrap_sketch_and_split(sketch, obj2.bRepBodies.item(0).faces.item(0), transform)
transform = adsk.core.Matrix3D.create()
transform.setToRotation(math.radians(-90),
adsk.core.Vector3D.create(0, 0, 1),
adsk.core.Point3D.create(0, 0, 0))
transform.translation = adsk.core.Vector3D.create(-1, 4, 0)
obj.transform = transform
transform = adsk.core.Matrix3D.create()
transform.setToRotation(math.radians(-90),
adsk.core.Vector3D.create(0, 0, 1),
adsk.core.Point3D.create(0, 0, 0))
transform.translation = adsk.core.Vector3D.create(4, 4, 2)
obj2.transform = transform
except:
traceback.print_exc()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment