Welcome to the Onshape forum! Ask questions and join in the discussions about everything Onshape.

First time visiting? Here are some places to start:

  1. Looking for a certain topic? Check out the categories filter or use Search (upper right).
  2. Need support? Ask a question to our Community Support category.
  3. Please submit support tickets for bugs but you can request improvements in the Product Feedback category.
  4. Be respectful, on topic and if you see a problem, Flag it.

If you would like to contact our Community Manager personally, feel free to send a private message or an email.

How do I scale skText in-situ from featurescript?

pmdpmd Member, Developers Posts: 22 PRO
Having read all the previous answers to this question and tried various combinations I still cannot work how to scale skText in-situ. The roman numeral clock example was too complex for me to adapt and the other simpler methods do not work for me.

I want to write a function I can call from other FS code to place a small text label on a face at the midpoint of an edge.

Here is current non-working attempt:


It scales the text ok using scaleUniformly but also ends up moving the origin of the text to the wrong Z value.

Is there a way to scale in X and Y and leave Z alone? I am guessing I need to create a special matrix somehow...


  • Jake_RosenfeldJake_Rosenfeld Moderator, Onshape Employees, Developers Posts: 1,162

    I think your best bet here is to use the 'transform' feature (the function that the button in the toolbar is tied to) rather than 'opTransform':

    transform(context, id + "transform", {
            "entities" : bodyQuery,
            "transformType" : TransformType.SCALE_UNIFORMLY,
            "scale" : scaleFactor,
            "scalePoint" : centerOfScaling // for example: `vector(1, 2, 3) * inch`

    If you'd rather do it yourself, this is analogous to using the following transform into opTransform:
    var scaleAboutPoint = transform(scalePoint) * scaleUniformly(scaleFactor) * transform(-scalePoint)
    Transforms are applied right-to-left; see documentation:

    You can think of this as:
    1. Move all the entities such that 'scalePoint' is at the origin (transform(-scalePoint))
    2. Scale the entities about the origin (scaleUniformly(scaleFactor))
    3. Move the entities back such that 'scalePoint' is at its original location (transform(scalePoint))
    Jake Rosenfeld - Modeling Team
  • pmdpmd Member, Developers Posts: 22 PRO
    Thanks Jake. It turns out I finally fully understood the roman numeral clock code after a bit more play and as I wanted to centre the text on midpoint of a line I needed to skSolve to get the bounding box before transforming it so the in-situ requirement went away.

    One thing which is confusing is the right-to-left reading of the transform multiplication expressions into English and the fact that  order matters a lot. It makes trial and error testing more difficult...
  • Jake_RosenfeldJake_Rosenfeld Moderator, Onshape Employees, Developers Posts: 1,162
    edited January 2018

    It's definitely tripped me up before too, I usually return to that page of documentation whenever I'm working on Transforms.

    As for the mathematical motivation behind this:
    An analog of what you're doing when transforming a part is 'moving every point of the part by the transform', so let's just think in terms of one point.   It's somewhat standard in linear algebra to represent position vectors (points) as 3x1 column vectors. Transforms are represented by 3x3 matrices†.  So, if I want to multiply the position and the matrix, I have to do (matrix * position), because (position * matrix) is not a valid matrix multiplication.  Now, if you think of your transform as a series of these multiplications, you'll see that you have to do the operation as follows:
    (doThisLast * doThisSecond * doThisFirst * position)
    so, the transform you're interested in is:
    (doThisLast * doThisSecond * doThisFirst)

    Of course, you can happily turn this all on its head by representing the position vector as a row vector, and taking the transpose of the transforms:
    (positionAsRow * doThisFirst' * doThisSecond' * doThisThird')
    where ' means transpose. 

    But at some point the math gods decided column vectors are better.  Probably because they take up less horizontal space when you're solving equations on a sheet of paper...

    † A note of clarification from a coworker:  FeatureScript Transforms are actually represented as the combination of a 3x3 matrix and an affine translation:
    but the ordering motivation holds 
    Jake Rosenfeld - Modeling Team
  • Jake_RosenfeldJake_Rosenfeld Moderator, Onshape Employees, Developers Posts: 1,162

    I made a mistake,  we actually have a `scaleUniformly(scale is number, point is Vector)` method.  Sorry for making everything more confusing than it needed to be.

    Jake Rosenfeld - Modeling Team
  • BulletEngineeringBulletEngineering Member Posts: 8 PRO
    You can control the text position and size by adding the following to the definition map:
     "firstCorner" : vector( xPosition, yPosition), 
    "secondCorner" : vector(xPosition+1*inch, yPosition + textHeight)

    Substitute the desired variable or value for xPosition, yPosition, and textHeight. Note that skText always starts from the most negative corner and works its way right (even when the reverse flag is true), and it will automatically scale the width of the text box to match the specified height. You still need to use transform if you want to rotate the text or anything fancy like that.


    var textStringToSketch = "Hello World";
    var xPosition = 1*inch;
    var yPosition = 3*inch;
    var fontHeight = .25 * inch;

    skText(rulerSketch, id + "text" ~ textStringToSketch, {
                                    "text" : textStringToSketch,
                                    "fontName" : "OpenSans-Regular.ttf",
                                    "mirrorVertical" : false,
                                    "mirrorHorizontal" : false,
                                    "firstCorner" : vector(xPosition, yPosition),
                                    "secondCorner" : vector(xPosition + 1 * inch, yPosition+ fontHeight)

  • Jake_RosenfeldJake_Rosenfeld Moderator, Onshape Employees, Developers Posts: 1,162

    Looks like some of us internally, myself included, were confused about the correct way to do this.  We'll be sure to document it for the upcoming release.  Thanks for the input.
    Jake Rosenfeld - Modeling Team
Sign In or Register to comment.