如何在处理中手动将矩阵堆栈应用于坐标
How to manually apply matrix stack to coordinates in processing
在处理过程中,当您应用矩阵变换时,您可以在 canvas 上绘图,而不必担心 x y 坐标的“真实”位置。
我认为按照同样的逻辑,我可以使用 ParentApplet.get(x, y, width, height) 复制 canvas 的一部分,它会自动移动 x 和y,但它没有,它使用坐标作为原始输入,而不对其应用矩阵堆栈。
因此,我认为处理该问题的最简单方法是手动将矩阵堆栈应用于我的 x、y、宽度、高度值,并将结果用作 get() 的输入。但是我找不到这样的功能,有吗?
编辑:根据要求,这是我的问题的一个例子
所以这里的objective就是画一个简单的形状,复制粘贴。不用translate也没问题:
void settings(){
size(500, 500);
}
void draw() {
background(255);
// Fancy rectangle for visibility
fill(255, 0 ,0);
rect(0, 0, 100, 100);
fill(0, 255, 0);
rect(20, 20, 60, 60);
// copy rectangle and paste it elsewhere
PImage img = get(0, 0, 101, 101);
image(img, 200, 200);
}
现在,如果我在绘制形状之前应用转换矩阵,我希望我可以使用相同的 get() 代码来复制完全相同的绘图:
void settings(){
size(500, 500);
}
void draw() {
background(255);
pushMatrix();
translate(10, 10);
// Fancy rectangle for visibility
fill(255, 0 ,0);
rect(0, 0, 100, 100);
fill(0, 255, 0);
rect(20, 20, 60, 60);
// copy rectangle and paste it elsewhere
PImage img = get(0, 0, 101, 101);
image(img, 200, 200);
popMatrix();
}
但它不是那样工作的,get(0, 0, ..) 不使用当前变换矩阵从原点 (10, 10) 复制像素:
能否提供更多详细信息。
可以使用 pushMatrix()/PopMatrix() 操纵坐标系,您可以更进一步,手动将矩阵和向量相乘。
令人困惑的部分是您正在调用 get(x,y,width,height)
但没有显示您如何呈现 PImage
部分。很难猜出您提到的矩阵堆栈。你能 post 一个示例片段吗?
如果您在调用 get()
时以相同的 x,y 渲染它,它应该以相同的 x,y 位移渲染:
size(640, 360);
noFill();
strokeWeight(9);
PImage placeholderForPGraphics = loadImage("https://processing.org/examples/moonwalk.jpg");
image(placeholderForPGraphics, 0, 0);
int x = 420;
int y = 120;
int w = 32;
int h = 48;
// visualise region of interest
rect(x, y, w, h);
// grab the section sub PImage
PImage section = placeholderForPGraphics.get(x, y, w, h);
//filter the section to make it really standout
section.filter(THRESHOLD);
// display section at same location
image(section, x, y);
关于矩阵栈,可以调用getMatrix()
which will return a PMatrix2D if you're in 2D mode (otherwise a PMatrix3D)。这是当前矩阵堆栈在您调用它的状态下的副本(任何先前的操作都将“烘焙”到此状态)。
例如:
PMatrix m = g.getMatrix();
printArray(m.get(new float[]{}));
(g.printMatrix()
应该更容易打印到控制台,但如果你需要一个实例来操作,你需要调用 getMatrix()
)
其中 g
是您的 PGraphics 实例。
然后您可以随心所欲地操作它:
m.translate(10, 20);
m.rotate(radians(30));
m.scale(1.5);
完成后记得调用applyMatrix()
它:
g.applyMatrix(m);
虽然这可能很琐碎,但我希望上面示例的这个修改版本能够说明这个想法:
size(640, 360);
noFill();
strokeWeight(9);
// get the current transformation matrix
PMatrix m = g.getMatrix();
// print to console
println("before");
g.printMatrix();
// modify it
m.translate(160, 90);
m.scale(0.5);
// apply it
g.applyMatrix(m);
// print applied matrix
println("after");
g.printMatrix();
PImage placeholderForPGraphics = loadImage("https://processing.org/examples/moonwalk.jpg");
image(placeholderForPGraphics, 0, 0);
int x = 420;
int y = 120;
int w = 32;
int h = 48;
// visualise region of interest
rect(x, y, w, h);
// grab the section sub PImage
PImage section = placeholderForPGraphics.get(x, y, w, h);
//filter the section to make it really standout
section.filter(THRESHOLD);
// display section at same location
image(section, x, y);
这是另一个使用矩阵变换将基础变成 PGraphics
的例子:
void setup(){
size(360, 360);
// draw something manipulating the coordinate system
PGraphics pg = createGraphics(360, 360);
pg.beginDraw();
pg.background(0);
pg.noFill();
pg.stroke(255, 128);
pg.strokeWeight(4.5);
pg.rectMode(CENTER);
pg.translate(180,180);
for(int i = 0 ; i < 72; i++){
pg.rotate(radians(5));
pg.scale(0.95);
//pg.rect(0, 0, 320, 320, 32, 32, 32, 32);
polygon(6, 180, pg);
}
pg.endDraw();
// render PGraphics
image(pg, 0, 0);
}
这太过分了:同样的效果本可以绘制得更简单,但是重点在于调用 get()
和使用变换矩阵。这里修改后的迭代显示与 get(x,y,w,h)
相同的原理,然后是 image(section,x,y)
:
void setup(){
size(360, 360);
// draw something manipulating the coordinate system
PGraphics pg = createGraphics(360, 360);
pg.beginDraw();
pg.background(0);
pg.noFill();
pg.stroke(255, 128);
pg.strokeWeight(4.5);
pg.rectMode(CENTER);
pg.translate(180,180);
for(int i = 0 ; i < 72; i++){
pg.rotate(radians(5));
pg.scale(0.95);
//pg.rect(0, 0, 320, 320, 32, 32, 32, 32);
polygon(6, 180, pg);
}
pg.endDraw();
// render PGraphics
image(pg, 0, 0);
// take a section of PGraphics instance
int w = 180;
int h = 180;
int x = (pg.width - w) / 2;
int y = (pg.height - h) / 2;
PImage section = pg.get(x, y, w, h);
// filter section to emphasise
section.filter(INVERT);
// render section at sampled location
image(section, x, y);
popMatrix();
}
void polygon(int sides, float radius, PGraphics pg){
float angleIncrement = TWO_PI / sides;
pg.beginShape();
for(int i = 0 ; i <= sides; i++){
float angle = (angleIncrement * i) + HALF_PI;
pg.vertex(cos(angle) * radius, sin(angle) * radius);
}
pg.endShape();
}
这是在孤立坐标 space 中重新应用最后一个变换矩阵的最终迭代(使用 push/pop 矩阵调用):
void setup(){
size(360, 360);
// draw something manipulating the coordinate system
PGraphics pg = createGraphics(360, 360);
pg.beginDraw();
pg.background(0);
pg.noFill();
pg.stroke(255, 128);
pg.strokeWeight(4.5);
pg.rectMode(CENTER);
pg.translate(180,180);
for(int i = 0 ; i < 72; i++){
pg.rotate(radians(5));
pg.scale(0.95);
//pg.rect(0, 0, 320, 320, 32, 32, 32, 32);
polygon(6, 180, pg);
}
pg.endDraw();
// render PGraphics
image(pg, 0, 0);
// take a section of PGraphics instance
int w = 180;
int h = 180;
int x = (pg.width - w) / 2;
int y = (pg.height - h) / 2;
PImage section = pg.get(x, y, w, h);
// filter section to emphasise
section.filter(INVERT);
// print last state of the transformation matrix
pg.printMatrix();
// get the last matrix state
PMatrix m = pg.getMatrix();
// isolate coordinate space
pushMatrix();
//apply last PGraphics matrix
applyMatrix(m);
// render section at sampled location
image(section, x, y);
popMatrix();
save("state3.png");
}
void polygon(int sides, float radius, PGraphics pg){
float angleIncrement = TWO_PI / sides;
pg.beginShape();
for(int i = 0 ; i <= sides; i++){
float angle = (angleIncrement * i) + HALF_PI;
pg.vertex(cos(angle) * radius, sin(angle) * radius);
}
pg.endShape();
}
这是一个极端的例子,因为 0.95
缩小应用了 72 次,因此渲染的图像非常小。还要注意旋转增加了。
Update 根据您的更新片段,似乎混淆是围绕 pushMatrix()
和 get()
.
在您的场景中,pushMatrix()/translate()
将偏移局部坐标系:即绘制元素的位置。
get()
全局调用,使用绝对坐标
如果您只使用平移,您可以简单地存储平移坐标并重新使用它们从同一位置采样:
int sampleX = 10;
int sampleY = 10;
void settings(){
size(500, 500);
}
void draw() {
background(255);
pushMatrix();
translate(sampleX, sampleY);
// Fancy rectangle for visibility
fill(255, 0 ,0);
rect(0, 0, 100, 100);
fill(0, 255, 0);
rect(20, 20, 60, 60);
// copy rectangle and paste it elsewhere
PImage img = get(sampleX, sampleY, 101, 101);
image(img, 200, 200);
popMatrix();
}
更新
这里有几个关于如何计算而不是硬编码翻译值的例子:
void settings(){
size(500, 500);
}
void setup() {
background(255);
pushMatrix();
translate(10, 10);
// Fancy rectangle for visibility
fill(255, 0 ,0);
rect(0, 0, 100, 100);
fill(0, 255, 0);
rect(20, 20, 60, 60);
// local to global coordinate conversion using PMatrix
// g is the global PGraphics instance every PApplet (sketch) uses
PMatrix m = g.getMatrix();
printArray(m.get(null));
// the point in local coordinate system
PVector local = new PVector(0,0);
// multiply local point by transformation matrix to get global point
// we pass in null to get a new PVector instance: you can make this more efficient by allocating a single PVector ad re-using it instead of this basic demo
PVector global = m.mult(local,null);
// copy rectangle and paste it elsewhere
println("local",local,"->global",global);
PImage img = get((int)global.x, (int)global.y, 101, 101);
image(img, 200, 200);
popMatrix();
}
要根据变换矩阵计算向量的位置,只需将该向量乘以该矩阵即可。非常粗略地说,push/pop 矩阵会发生什么(每个 push/pop 堆栈都使用一个变换矩阵,然后一直乘以全局坐标系)。 (还要注意对 efficienty/pre-allocating 矩阵和向量的注释)。
这在代码方面会更加冗长,如果您使用大量嵌套转换,则可能需要一些规划,但是您可以更好地控制选择使用哪些转换。
一个更简单的解决方案可能是切换到 P3D
OpenGL 渲染器,它允许您使用 screenX()
, screenY()
进行此转换。 (同时结帐 modelX()
/modelY()
)
void settings(){
size(500, 500, P3D);
}
void draw() {
background(255);
pushMatrix();
translate(10, 10);
// Fancy rectangle for visibility
fill(255, 0 ,0);
rect(0, 0, 100, 100);
fill(0, 255, 0);
rect(20, 20, 60, 60);
// local to global coordinate conversion using modelX,modelY
float x = screenX(0, 0, 0);
float y = screenY(0, 0, 0);
println(x,y);
PImage img = get((int)x, (int)y, 101, 101);
image(img, 200, 200);
popMatrix();
}
请记住,您想要抓取一个仅应用了翻译的矩形。由于 get()
不会考虑 rotation/scale,对于更复杂的情况,您可能希望将局部坐标转换为全局坐标,不仅是左上角的坐标,还包括右下角的偏移坐标。这个想法是在变换后的框周围计算更大的边界框(没有旋转),所以当你调用 get()
时,整个感兴趣的区域都会被返回(而不仅仅是剪切的部分)。
在处理过程中,当您应用矩阵变换时,您可以在 canvas 上绘图,而不必担心 x y 坐标的“真实”位置。
我认为按照同样的逻辑,我可以使用 ParentApplet.get(x, y, width, height) 复制 canvas 的一部分,它会自动移动 x 和y,但它没有,它使用坐标作为原始输入,而不对其应用矩阵堆栈。
因此,我认为处理该问题的最简单方法是手动将矩阵堆栈应用于我的 x、y、宽度、高度值,并将结果用作 get() 的输入。但是我找不到这样的功能,有吗?
编辑:根据要求,这是我的问题的一个例子
所以这里的objective就是画一个简单的形状,复制粘贴。不用translate也没问题:
void settings(){
size(500, 500);
}
void draw() {
background(255);
// Fancy rectangle for visibility
fill(255, 0 ,0);
rect(0, 0, 100, 100);
fill(0, 255, 0);
rect(20, 20, 60, 60);
// copy rectangle and paste it elsewhere
PImage img = get(0, 0, 101, 101);
image(img, 200, 200);
}
现在,如果我在绘制形状之前应用转换矩阵,我希望我可以使用相同的 get() 代码来复制完全相同的绘图:
void settings(){
size(500, 500);
}
void draw() {
background(255);
pushMatrix();
translate(10, 10);
// Fancy rectangle for visibility
fill(255, 0 ,0);
rect(0, 0, 100, 100);
fill(0, 255, 0);
rect(20, 20, 60, 60);
// copy rectangle and paste it elsewhere
PImage img = get(0, 0, 101, 101);
image(img, 200, 200);
popMatrix();
}
但它不是那样工作的,get(0, 0, ..) 不使用当前变换矩阵从原点 (10, 10) 复制像素:
能否提供更多详细信息。 可以使用 pushMatrix()/PopMatrix() 操纵坐标系,您可以更进一步,手动将矩阵和向量相乘。
令人困惑的部分是您正在调用 get(x,y,width,height)
但没有显示您如何呈现 PImage
部分。很难猜出您提到的矩阵堆栈。你能 post 一个示例片段吗?
如果您在调用 get()
时以相同的 x,y 渲染它,它应该以相同的 x,y 位移渲染:
size(640, 360);
noFill();
strokeWeight(9);
PImage placeholderForPGraphics = loadImage("https://processing.org/examples/moonwalk.jpg");
image(placeholderForPGraphics, 0, 0);
int x = 420;
int y = 120;
int w = 32;
int h = 48;
// visualise region of interest
rect(x, y, w, h);
// grab the section sub PImage
PImage section = placeholderForPGraphics.get(x, y, w, h);
//filter the section to make it really standout
section.filter(THRESHOLD);
// display section at same location
image(section, x, y);
关于矩阵栈,可以调用getMatrix()
which will return a PMatrix2D if you're in 2D mode (otherwise a PMatrix3D)。这是当前矩阵堆栈在您调用它的状态下的副本(任何先前的操作都将“烘焙”到此状态)。
例如:
PMatrix m = g.getMatrix();
printArray(m.get(new float[]{}));
(g.printMatrix()
应该更容易打印到控制台,但如果你需要一个实例来操作,你需要调用 getMatrix()
)
其中 g
是您的 PGraphics 实例。
然后您可以随心所欲地操作它:
m.translate(10, 20);
m.rotate(radians(30));
m.scale(1.5);
完成后记得调用applyMatrix()
它:
g.applyMatrix(m);
虽然这可能很琐碎,但我希望上面示例的这个修改版本能够说明这个想法:
size(640, 360);
noFill();
strokeWeight(9);
// get the current transformation matrix
PMatrix m = g.getMatrix();
// print to console
println("before");
g.printMatrix();
// modify it
m.translate(160, 90);
m.scale(0.5);
// apply it
g.applyMatrix(m);
// print applied matrix
println("after");
g.printMatrix();
PImage placeholderForPGraphics = loadImage("https://processing.org/examples/moonwalk.jpg");
image(placeholderForPGraphics, 0, 0);
int x = 420;
int y = 120;
int w = 32;
int h = 48;
// visualise region of interest
rect(x, y, w, h);
// grab the section sub PImage
PImage section = placeholderForPGraphics.get(x, y, w, h);
//filter the section to make it really standout
section.filter(THRESHOLD);
// display section at same location
image(section, x, y);
这是另一个使用矩阵变换将基础变成 PGraphics
的例子:
void setup(){
size(360, 360);
// draw something manipulating the coordinate system
PGraphics pg = createGraphics(360, 360);
pg.beginDraw();
pg.background(0);
pg.noFill();
pg.stroke(255, 128);
pg.strokeWeight(4.5);
pg.rectMode(CENTER);
pg.translate(180,180);
for(int i = 0 ; i < 72; i++){
pg.rotate(radians(5));
pg.scale(0.95);
//pg.rect(0, 0, 320, 320, 32, 32, 32, 32);
polygon(6, 180, pg);
}
pg.endDraw();
// render PGraphics
image(pg, 0, 0);
}
这太过分了:同样的效果本可以绘制得更简单,但是重点在于调用 get()
和使用变换矩阵。这里修改后的迭代显示与 get(x,y,w,h)
相同的原理,然后是 image(section,x,y)
:
void setup(){
size(360, 360);
// draw something manipulating the coordinate system
PGraphics pg = createGraphics(360, 360);
pg.beginDraw();
pg.background(0);
pg.noFill();
pg.stroke(255, 128);
pg.strokeWeight(4.5);
pg.rectMode(CENTER);
pg.translate(180,180);
for(int i = 0 ; i < 72; i++){
pg.rotate(radians(5));
pg.scale(0.95);
//pg.rect(0, 0, 320, 320, 32, 32, 32, 32);
polygon(6, 180, pg);
}
pg.endDraw();
// render PGraphics
image(pg, 0, 0);
// take a section of PGraphics instance
int w = 180;
int h = 180;
int x = (pg.width - w) / 2;
int y = (pg.height - h) / 2;
PImage section = pg.get(x, y, w, h);
// filter section to emphasise
section.filter(INVERT);
// render section at sampled location
image(section, x, y);
popMatrix();
}
void polygon(int sides, float radius, PGraphics pg){
float angleIncrement = TWO_PI / sides;
pg.beginShape();
for(int i = 0 ; i <= sides; i++){
float angle = (angleIncrement * i) + HALF_PI;
pg.vertex(cos(angle) * radius, sin(angle) * radius);
}
pg.endShape();
}
这是在孤立坐标 space 中重新应用最后一个变换矩阵的最终迭代(使用 push/pop 矩阵调用):
void setup(){
size(360, 360);
// draw something manipulating the coordinate system
PGraphics pg = createGraphics(360, 360);
pg.beginDraw();
pg.background(0);
pg.noFill();
pg.stroke(255, 128);
pg.strokeWeight(4.5);
pg.rectMode(CENTER);
pg.translate(180,180);
for(int i = 0 ; i < 72; i++){
pg.rotate(radians(5));
pg.scale(0.95);
//pg.rect(0, 0, 320, 320, 32, 32, 32, 32);
polygon(6, 180, pg);
}
pg.endDraw();
// render PGraphics
image(pg, 0, 0);
// take a section of PGraphics instance
int w = 180;
int h = 180;
int x = (pg.width - w) / 2;
int y = (pg.height - h) / 2;
PImage section = pg.get(x, y, w, h);
// filter section to emphasise
section.filter(INVERT);
// print last state of the transformation matrix
pg.printMatrix();
// get the last matrix state
PMatrix m = pg.getMatrix();
// isolate coordinate space
pushMatrix();
//apply last PGraphics matrix
applyMatrix(m);
// render section at sampled location
image(section, x, y);
popMatrix();
save("state3.png");
}
void polygon(int sides, float radius, PGraphics pg){
float angleIncrement = TWO_PI / sides;
pg.beginShape();
for(int i = 0 ; i <= sides; i++){
float angle = (angleIncrement * i) + HALF_PI;
pg.vertex(cos(angle) * radius, sin(angle) * radius);
}
pg.endShape();
}
这是一个极端的例子,因为 0.95
缩小应用了 72 次,因此渲染的图像非常小。还要注意旋转增加了。
Update 根据您的更新片段,似乎混淆是围绕 pushMatrix()
和 get()
.
在您的场景中,pushMatrix()/translate()
将偏移局部坐标系:即绘制元素的位置。
get()
全局调用,使用绝对坐标
如果您只使用平移,您可以简单地存储平移坐标并重新使用它们从同一位置采样:
int sampleX = 10;
int sampleY = 10;
void settings(){
size(500, 500);
}
void draw() {
background(255);
pushMatrix();
translate(sampleX, sampleY);
// Fancy rectangle for visibility
fill(255, 0 ,0);
rect(0, 0, 100, 100);
fill(0, 255, 0);
rect(20, 20, 60, 60);
// copy rectangle and paste it elsewhere
PImage img = get(sampleX, sampleY, 101, 101);
image(img, 200, 200);
popMatrix();
}
更新 这里有几个关于如何计算而不是硬编码翻译值的例子:
void settings(){
size(500, 500);
}
void setup() {
background(255);
pushMatrix();
translate(10, 10);
// Fancy rectangle for visibility
fill(255, 0 ,0);
rect(0, 0, 100, 100);
fill(0, 255, 0);
rect(20, 20, 60, 60);
// local to global coordinate conversion using PMatrix
// g is the global PGraphics instance every PApplet (sketch) uses
PMatrix m = g.getMatrix();
printArray(m.get(null));
// the point in local coordinate system
PVector local = new PVector(0,0);
// multiply local point by transformation matrix to get global point
// we pass in null to get a new PVector instance: you can make this more efficient by allocating a single PVector ad re-using it instead of this basic demo
PVector global = m.mult(local,null);
// copy rectangle and paste it elsewhere
println("local",local,"->global",global);
PImage img = get((int)global.x, (int)global.y, 101, 101);
image(img, 200, 200);
popMatrix();
}
要根据变换矩阵计算向量的位置,只需将该向量乘以该矩阵即可。非常粗略地说,push/pop 矩阵会发生什么(每个 push/pop 堆栈都使用一个变换矩阵,然后一直乘以全局坐标系)。 (还要注意对 efficienty/pre-allocating 矩阵和向量的注释)。
这在代码方面会更加冗长,如果您使用大量嵌套转换,则可能需要一些规划,但是您可以更好地控制选择使用哪些转换。
一个更简单的解决方案可能是切换到 P3D
OpenGL 渲染器,它允许您使用 screenX()
, screenY()
进行此转换。 (同时结帐 modelX()
/modelY()
)
void settings(){
size(500, 500, P3D);
}
void draw() {
background(255);
pushMatrix();
translate(10, 10);
// Fancy rectangle for visibility
fill(255, 0 ,0);
rect(0, 0, 100, 100);
fill(0, 255, 0);
rect(20, 20, 60, 60);
// local to global coordinate conversion using modelX,modelY
float x = screenX(0, 0, 0);
float y = screenY(0, 0, 0);
println(x,y);
PImage img = get((int)x, (int)y, 101, 101);
image(img, 200, 200);
popMatrix();
}
请记住,您想要抓取一个仅应用了翻译的矩形。由于 get()
不会考虑 rotation/scale,对于更复杂的情况,您可能希望将局部坐标转换为全局坐标,不仅是左上角的坐标,还包括右下角的偏移坐标。这个想法是在变换后的框周围计算更大的边界框(没有旋转),所以当你调用 get()
时,整个感兴趣的区域都会被返回(而不仅仅是剪切的部分)。