How to name a PShape child?

edited September 2016 in How To...

Is there a way of naming a PShape child?

I can't see anything in a PShape constructor or in PShape methods, but I may be missing something about how shape parameters work -- given that there is a way of retrieving a child by name it seems like there must be a way of naming.

For example, you can use getChild(String target) e.g. getChild("OH") to retrieve a child by its name. However neither addChild() nor createShape() appear to give a way of supplying that name in the first place. How is it done?

I provided a working example below. Child name lookup is particularly convenient in coding using removeChild() (not shown here) as the index numbers shift when a child is removed.

/**
 * How to name a PShape child?
 * 2016-09-06
 *
 * example adapted from processing.org/reference/PShape_addChild_.html
 */

PShape group;
PShape child;
PShape searchIndex;
PShape searchName;

void setup() {
  size(200,200);

  //// Make a group PShape
  group = createShape(GROUP);
  println("Group shape        = ", group);

  //// Make a child shape
  child = createShape();
  child.beginShape();
  child.vertex(-20, -20);
  child.vertex(0, -40);
  child.vertex(20, -20);
  child.endShape();

  //// Add child to group
  //// HOW TO SPECIFY A NAME?
  group.addChild(child);

  //// Get child by index
  searchIndex = group.getChild(0);
  println("Child index search = ", searchIndex);

  //// Get child by name
  //// see for example: https://processing.org/reference/PShape_getChild_.html
  ////   ohio = states.getChild("OH");
  //// NO NAME SO RETURNS NULL
  searchName = group.getChild("");
  println("Child name search  = ", searchName);
}

void draw() {
  background(52);
  if(group!=null){
    shape(group, width*1/5, height/2);
    shape(group.getChild(0), width*2/5, height/2);
  }  
  if(searchIndex!=null){
    shape(searchIndex, width*3/5, height/2);
  }
  if(searchName!=null){
    //// NOT CALLED WITHOUT NAME LOOKUP
    shape(searchName, width*4/5, height/2);
  }
}

Any advice on how to name a child? Sorry if this is obvious and I'm just not finding it.

Answers

  • Answer ✓

    I think maybe PShape is a class that is trying to be two things at once. In one mode you can use it to load svg files, and these can contain named children. And in another mode you can use it to store groups of shapes, which it calls children, but you can't name these. getChild by name will work with svg mode, not the other mode.

    (We saw someone having a similar but opposite problem yesterday - was using svg mode and trying to get a list of the vertices, which only works in vertices mode)

  • edited September 2016

    (In guessing the states in the original example came from an svg file, which is why that worked)

  • edited September 2016

    koogs, this observation about svg loading was very helpful. I was confused because I incorrectly assumed that you could name children -- that name metadata could be directly attached to an indexed PShape child (in particular because removeChild() changes the indexes of subsequent children). It looks like that isn't why PShape naming exists or how it works.

    PShape shape keeps two unsynced lists of subshapes:

    1. an addChild() index (int)
    2. an addName() hashmap (String).

    Subshapes can be both indexed children and named or just indexed, or just named.

    • Shapes in the child list are automatically rendered by shape().
    • Shapes in the name list are NOT rendered automatically -- they are only looked up.

    If you removeChild() a subshape will still be listed by name. There is no removeName(), and there doesn't appear to be a way to remove a name except by deleting the PShape entirely and creating a new one.

    I've put together a demo here that shows this in action:

    /**
     * PShape children and names
     * 2016-09-06
     */
    
    PShape group;
    PShape smallChild;
    PShape largeName;
    PShape removedChildName;
    
    void setup(){
      size(200,200);
    
      //// Create a group shape
      group = createShape(GROUP);
    
      //// Create three sub-shapes for testing
      smallChild = createShape(RECT, 15, 30, 20, 20);
      smallChild.rotate(-PI/8);
      largeName = createShape(RECT, 50, 50, 100, 100);
    
      //// Add a child shape -- WILL be drawn by: shape(group)
      group.addChild(smallChild);
      //// Add a named shape -- WON'T be drawn by: shape(group)
      group.addName("LARGE", largeName);
    
      //// Add a child shape inline
      group.addChild(createShape(QUAD, 20, 170, 180, 170, 190, 190, 10, 190));
      //// Give the last child a named lookup
      group.addName("REMOVED", group.getChild(group.getChildCount()-1));
      //// Remove the shape from the children list.
      group.removeChild(group.getChildCount()-1);
      //// The shape still exists in the name list and will display when called.
      //// There is no removeName() -- apparently names cannot be removed.
    }
    
    void draw(){
      background(192);
      //// Draw group -- shows only addChild, not addName
      shape(group,0,0);
    
      //// Draw group again by explicitly looping through children
      //// -- doesn't show named shapes.
      for(PShape child_ : group.getChildren()){
        shape(child_,5,5);
      }
      //// Not being drawn with group -- hide with click
      if(!mousePressed){
        //// a name shape that was never added to children
        shape(group.getChild("LARGE"),0,0);
        //// a name shape after being added to children then removed
        shape(group.getChild("REMOVED"),0,0);
      }
    }
    

    So -- there ARE ways to manage named shapes in a created group PShape, although looks like this functionality was really intended for SVG data (named objects need to be added to the children index separately, can't be removed, ect.) Still, interesting. Especially given that PShape doesn't have methods like removeVector() and doesn't have copy(), using child shapes (even a single child shape per group object) is one workaround if you want to create persistent shape objects that are editable in Processing.

Sign In or Register to comment.