PShape
Data / CompositeDescription
Datatype for storing shapes. Load with loadShape() or build programmatically with createShape().
Syntax
PShape* s = loadShape("file.svg")
PShape s = createShape()
Parameters
None
Returns
PShapeMethods
| getChild(int i) | Get child shape by index |
| getChild(std::string name) | Get child shape by name/id |
| getChildCount() | Number of children |
| getVertex(int i) | Get vertex by index as PVector |
| getVertexCount() | Number of vertices |
| setVertex(int i, float x, float y) | Set vertex position |
| disableStyle() | Ignore the shape's own fill/stroke |
| enableStyle() | Use the shape's own fill/stroke |
| setFill(float r, float g, float b) | Set fill color |
| setStroke(float r, float g, float b) | Set stroke color |
| width | Bounding box width |
| height | Bounding box height |
Related
Under the Hood
From Processing.h:
class PShape {
public:
struct Vertex { float x,y,z,u,v; };
std::vector<Vertex> verts;
std::vector<PShape> children;
int kind = -1;
bool closed = false;
bool visible = true;
float fillR=1,fillG=1,fillB=1,fillA=1;
float strokeR=0,strokeG=0,strokeB=0,strokeA=1,strokeW=1;
bool hasFill=true, hasStroke=false;
PShape() = default;
explicit PShape(int k) : kind(k) {}
// Allow PShape bot = loadShape("file.svg") -- copies from pointer
PShape(const PShape* p) { if(p) *this = *p; }
PShape& operator=(const PShape* p) { if(p) *this = *p; return *this; }
void beginShape(int k=-1) { kind=k; verts.clear(); }
void endShape(bool close=false) { closed=close; }
void vertex(float x,float y,float z=0,float u=0,float v=0) { verts.push_back({x,y,z,u,v}); }
void addChild(const PShape& s) { children.push_back(s); }
std::string name; // id/name attribute from SVG
std::vector<int> subpathStarts; // subpath start indices for multi-part fills
std::vector<Vertex> anchorVerts; // raw anchor points (M/L/C endpoints only) for getVertex()
PShape* getChild(int i) { return i<(int)children.size()?&children[i]:nullptr; }
PShape* getChild(const std::string& n) {
for(auto& c:children) if(c.name==n) return &c;
for(auto& c:children){ PShape* r=c.getChild(n); if(r) return r; }
// Return a static empty shape rather than nullptr to prevent crashes
static PShape _empty;
fprintf(stderr,"[PShape] getChild('%s') not found\n", n.c_str());
return &_empty;
}
PShape* getChild(const char* n) { return getChild(std::string(n)); }
int getChildCount() const { return (int)children.size(); }
PVector getVertex(int i) const {
if(i<0||i>=(int)verts.size()) return PVector(0,0,0);
return PVector(verts[i].x, verts[i].y, verts[i].z);
}
void setVertex(int i, float x, float y) {
if(i>=0&&i<(int)verts.size()){verts[i].x=x;verts[i].y=y;}
}
void setVertex(int i, float x, float y, float z) {
if(i>=0&&i<(int)verts.size()){verts[i].x=x;verts[i].y=y;verts[i].z=z;}
}
// Bounding box (computed from verts + children)
float width = 0;
float height = 0;
void computeBounds() {
float minx=1e9,maxx=-1e9,miny=1e9,maxy=-1e9;
for(auto& v:verts){minx=std::min(minx,v.x);maxx=std::max(maxx,v.x);miny=std::min(miny,v.y);maxy=std::max(maxy,v.y);}
for(auto& c:children){const_cast<PShape&>(c).computeBounds();minx=std::min(minx,c.verts.empty()?minx:minx);
if(!c.verts.empty()){for(auto& v:c.verts){minx=std::min(minx,v.x);maxx=std::max(maxx,v.x);miny=std::min(miny,v.y);maxy=std::max(maxy,v.y);}}}
width =(maxx>-1e8)?(maxx-minx):0;
height=(maxy>-1e8)?(maxy-miny):0;
}
int getVertexCount() const { return (int)verts.size(); }
void setFill(float r,float g,float b,float a=1) { fillR=r;fillG=g;fillB=b;fillA=a;hasFill=true; }
void setStroke(float r,float g,float b,float a=1) { strokeR=r;strokeG=g;strokeB=b;strokeA=a;hasStroke=true; }
void setStrokeWeight(float w) { strokeW=w; }
void setVisible(bool v) { visible=v; }
void translate(float x,float y,float z=0) { for(auto& v:verts){ v.x+=x;v.y+=y;v.z+=z; } }
void scale(float s) { for(auto& v:verts){ v.x*=s;v.y*=s;v.z*=s; } }
void scale(float sx, float sy) { for(auto& v:verts){ v.x*=sx;v.y*=sy; } }
// Style enable/disable -- controls whether shape uses its own fill/stroke
// or inherits from the current Processing fill()/stroke() state
bool styleEnabled = true;
void disableStyle() { styleEnabled = false; }
void enableStyle() { styleEnabled = true; }
GLuint texId = 0; // OpenGL texture ID for OBJ material textures
};
Under the Hood
From Processing.cpp:
PShape PApplet::createShape(int kind){ return PShape(kind);
if(found.empty()){std::cerr<<"loadShape: file not found: "<<path<<"\n";return new PShape();
if(found.empty()){std::cerr<<"loadShape: OBJ not found: "<<path<<"\n";return new PShape();
return new PShape();