チュートリアル | (トピック一覧へ戻る) |
ばね力とパーティクルによる線エージェントまず最初のコードでは分岐を行う線エージェントLineAgentクラス を作成しますが。このクラスは以前のチュートリアルの分岐エージェント に類似していますが、 IAgentクラスではなくIParticleクラスを継承して作成することにより 力の場や張力に反応できるようにします。 そしてアップデート・メソッドでは、線を生成するだけではなく、張力を持った線エージェントでもある ISpringLineを生成し、端点に自分のパーティクルと、子エージェントのパーティクルを繋ぎます。
![]()
![]()
![]()
import igeo.*;
import processing.opengl.*;
void setup(){
size(480,360,IG.GL);
new LineAgent(new IParticle(0,0,0).hide().fric(0.2),
new IVec(0,2,0));
IG.bg(1.0,1.0,1.0);
IG.top();
}
class LineAgent extends IParticle{
LineAgent parent;
IVec dir;
LineAgent(IParticle parent, IVec dir){
super(parent.pos().cp(dir));
if(parent instanceof LineAgent){
this.parent = (LineAgent)parent;
}
hide(); // hide point
this.dir = dir;
fric(0.2);
}
void update(){
if(time()==0 && alive()){
if(parent!=null && parent.alive()){
//line between this and parent with spring force 100
new ISpringLine(this,parent,100).clr(0);
}
new LineAgent(this, dir);
}
}
}
下のコードでは複数のアトラクタ―により力の場を形成して、 線エージェントの反応する様子を見ます。
![]()
![]()
![]()
import igeo.*;
import processing.opengl.*;
void setup(){
size(480,360,IG.GL);
new LineAgent(new IParticle(0,0,0).hide().fric(0.2),
new IVec(0,2,0));
for(int i=0; i < 20; i++){
new IAttractor(IRand.pt(-200,0,0,200,400,0)).linear(100).intensity(-200); //repulsion force
}
IG.bg(1.0,1.0,1.0);
IG.top();
}
class LineAgent extends IParticle{
LineAgent parent;
IVec dir;
LineAgent(IParticle parent, IVec dir){
super(parent.pos().cp(dir));
if(parent instanceof LineAgent){
this.parent = (LineAgent)parent;
}
hide(); // hide point
this.dir = dir;
fric(0.2);
}
void update(){
if(time()==0 && alive()){
if(parent!=null && parent.alive()){
new ISpringLine(this,parent,100).clr(0); //line with spring force
}
new LineAgent(this, dir);
}
}
}
分岐動作の追加
![]()
![]()
![]()
import igeo.*;
import processing.opengl.*;
void setup(){
size(480,360,IG.GL);
for(int i=0; i < 4; i++){
new LineAgent(new IParticle(IRand.pt(-40,-40,0,40,40,0)).hide().fric(0.2), IRand.dir(IG.zaxis).len(2));
}
for(int i=0; i < 20; i++){
new IAttractor(IRand.pt(-200,0,0,200,400,0)).linear(100).intensity(-200); //repulsion force
}
IG.bg(1.0,1.0,1.0);
IG.top();
}
class LineAgent extends IParticle{
LineAgent parent;
IVec dir;
LineAgent(IParticle parent, IVec dir){
super(parent.pos().cp(dir));
if(parent instanceof LineAgent){
this.parent = (LineAgent)parent;
}
hide(); // hide point
this.dir = dir;
fric(0.2);
}
void update(){
if(time()==0 && alive()){
if(parent!=null && parent.alive()){
ISpringLine ln = new ISpringLine(this, parent,100); //line with spring force
double t = -cos(IG.time()*0.06)*0.5+0.5;
ln.hsb( 0.7-t*0.2, 1, 0.8-t*0.2); //color by time
}
new LineAgent(this, dir);
IVec dir2 = dir.cp();
dir2.rot(PI*0.12);
if( IRand.pct(5) ){ // 5% branching probability
new LineAgent(this,dir2);
}
}
}
}
衝突判定
![]()
![]()
![]()
import igeo.*;
import processing.opengl.*;
void setup(){
size(480,360,IG.GL);
for(int i=0; i < 4; i++){
new LineAgent(new IParticle(IRand.pt(-40,-40,0,40,40,0)).hide().fric(0.2), IRand.dir(IG.zaxis).len(2));
}
for(int i=0; i < 20; i++){
new IAttractor(IRand.pt(-200,0,0,200,400,0)).linear(100).intensity(-200); //repulsion force
}
IG.bg(1.0,1.0,1.0);
IG.top();
}
class LineAgent extends IParticle{
LineAgent parent;
boolean isColliding;
IVec dir;
LineAgent(IParticle parent, IVec dir){
super(parent.pos().cp(dir));
if(parent instanceof LineAgent){
this.parent = (LineAgent)parent;
}
isColliding=false;
hide(); // hide point
this.dir = dir;
fric(0.2);
}
void interact(ArrayList agents){
if(time()==0){ //only in the first time
for(int i=0; i < agents.size(); i++){
if(agents.get(i) instanceof LineAgent){
LineAgent lineAgent = (LineAgent)agents.get(i);
if(lineAgent!=this){ //agents include "this"
if(lineAgent.parent!=null && lineAgent.pos().dist(pos()) < pos().dist(parent.pos())*2){
IVec intxn = IVec.intersectSegment(lineAgent.parent.pos(),lineAgent.pos(),parent.pos(),pos());
if(intxn != null && !intxn.eq(parent.pos()) && !lineAgent.isColliding ){
isColliding = true;
return;
}
}
}
}
}
}
}
void update(){
if( isColliding ){
del();
}
else{
if(time()==0 && alive()){
if(parent!=null && parent.alive()){
ISpringLine ln = new ISpringLine(this, parent,100);
double t = -cos(IG.time()*0.06)*0.5+0.5;
ln.hsb( 0.7-t*0.2, 1, 0.8-t*0.2, 1.0); // color by time
}
new LineAgent(this, dir);
IVec dir2 = dir.cp();
dir2.rot(PI*0.12);
if( IRand.pct(5) ){ // 5% branching probability
new LineAgent(this,dir2);
}
}
}
}
}
分岐と成長角度の制御![]()
![]()
![]()
import igeo.*;
import processing.opengl.*;
void setup(){
size(480,360,IG.GL);
for(int i=0; i < 4; i++){
new LineAgent(new IParticle(IRand.pt(-40,-40,0,40,40,0)).hide().fric(0.2), IRand.dir(IG.zaxis).len(2));
}
for(int i=0; i < 20; i++){
new IAttractor(IRand.pt(-200,-200,0,200,200,0)).linear(50).intensity(-100); //repulsion force
}
IG.bg(1.0,1.0,1.0);
IG.top();
}
class LineAgent extends IParticle{
LineAgent parent;
boolean isColliding;
IVec dir;
LineAgent(IParticle parent, IVec dir){
super(parent.pos().cp(dir));
if(parent instanceof LineAgent){
this.parent = (LineAgent)parent;
}
isColliding=false;
hide(); // hide point
this.dir = dir;
fric(0.2);
}
void interact(ArrayList agents){
if(time()==0){ //only in the first time
for(int i=0; i < agents.size(); i++){
if(agents.get(i) instanceof LineAgent){
LineAgent lineAgent = (LineAgent)agents.get(i);
if(lineAgent!=this){ //agents include "this"
if(lineAgent.parent!=null && lineAgent.pos().dist(pos()) < pos().dist(parent.pos())*2){
IVec intxn = IVec.intersectSegment(lineAgent.parent.pos(),lineAgent.pos(),parent.pos(),pos());
if( intxn != null && !intxn.eq(parent.pos()) && !lineAgent.isColliding ){
isColliding = true;
return;
}
}
}
}
}
}
}
void update(){
if( isColliding ){
del();
}
else{
if(time()==0 && alive()){
if(parent!=null && parent.alive()){
ISpringLine ln = new ISpringLine(this, parent,100);
double t = -cos(IG.time()*0.06)*0.5+0.5;
ln.hsb( 0.7-t*0.2, 1, 0.8-t*0.2, 1.0); // color by time
}
IVec dir2 = dir.cp();
double angle = PI*0.12 ;
if( IRand.pct(50) ){
dir.rot(angle);
dir2.rot(-angle);
}
else{
dir.rot(-angle);
dir2.rot(angle);
}
new LineAgent(this, dir);
if( IRand.pct(20) ){ // 20% branching probability
new LineAgent(this,dir2);
}
}
}
}
}
ばねの長さの設定
![]()
![]()
![]()
import igeo.*;
import processing.opengl.*;
void setup(){
size(480,360,IG.GL);
for(int i=0; i < 4; i++){
new LineAgent(new IParticle(IRand.pt(-40,-40,0,40,40,0)).hide().fric(0.2), IRand.dir(IG.zaxis).len(2));
}
for(int i=0; i < 20; i++){
new IAttractor(IRand.pt(-200,-200,0,200,200,0)).linear(50).intensity(-100); //repulsion force
}
IG.bg(1.0,1.0,1.0);
IG.top();
}
class LineAgent extends IParticle{
LineAgent parent;
boolean isColliding;
IVec dir;
LineAgent(IParticle parent, IVec dir){
super(parent.pos().cp(dir));
if(parent instanceof LineAgent){
this.parent = (LineAgent)parent;
}
isColliding=false;
hide(); // hide point
this.dir = dir;
fric(0.2);
}
void interact(ArrayList agents){
if(time()==0){ //only in the first time
for(int i=0; i < agents.size(); i++){
if(agents.get(i) instanceof LineAgent){
LineAgent lineAgent = (LineAgent)agents.get(i);
if(lineAgent!=this){ //agents include "this"
if(lineAgent.parent!=null && lineAgent.pos().dist(pos()) < pos().dist(parent.pos())*2){
IVec intxn = IVec.intersectSegment(lineAgent.parent.pos(),lineAgent.pos(),parent.pos(),pos());
if( intxn != null && !intxn.eq(parent.pos()) && !lineAgent.isColliding ){
isColliding = true;
return;
}
}
}
}
}
}
}
void update(){
if( isColliding ){
del();
}
else{
if(time()==0 && alive()){
if(parent!=null && parent.alive()){
ISpringLine ln = new ISpringLine(this, parent,100);
double t = -cos(IG.time()*0.06)*0.5+0.5;
ln.hsb( 0.7-t*0.2, 1, 0.8-t*0.2, 1.0);
ln.len(ln.len()*2); //set spring length longer
}
IVec dir2 = dir.cp();
double angle = PI*0.12 ;
if( IRand.pct(50) ){
dir.rot(angle);
dir2.rot(-angle);
}
else{
dir.rot(-angle);
dir2.rot(angle);
}
new LineAgent(this, dir);
if( IRand.pct(20) ){ // 20% branching probability
new LineAgent(this,dir2);
}
}
}
}
}
分岐パーティクル・エージェントが成長してゆくなかで、ばねがさらに伸びようとする結果、 線がジグザグに荒れる現象が見られます。
板ばね力による線の円滑化![]()
![]()
![]()
import igeo.*;
import processing.opengl.*;
void setup(){
size(480,360,IG.GL);
for(int i=0; i < 4; i++){
new LineAgent(new IParticle(IRand.pt(-40,-40,0,40,40,0)).hide().fric(0.2), IRand.dir(IG.zaxis).len(2));
}
for(int i=0; i < 20; i++){
new IAttractor(IRand.pt(-200,-200,0,200,200,0)).linear(50).intensity(-30); //repulsion force
}
IG.bg(1.0,1.0,1.0);
IG.top();
}
class LineAgent extends IParticle{
LineAgent parent;
boolean isColliding;
IVec dir;
LineAgent(IParticle parent, IVec dir){
super(parent.pos().cp(dir));
if(parent instanceof LineAgent){
this.parent = (LineAgent)parent;
}
isColliding=false;
hide(); // hide point
this.dir = dir;
fric(0.2);
}
void interact(ArrayList agents){
if(time()==0){ //only in the first time
for(int i=0; i < agents.size(); i++){
if(agents.get(i) instanceof LineAgent){
LineAgent lineAgent = (LineAgent)agents.get(i);
if(lineAgent!=this){ //agents include "this"
if(lineAgent.parent!=null && lineAgent.pos().dist(pos()) < pos().dist(parent.pos())*2){
IVec intxn = IVec.intersectSegment(lineAgent.parent.pos(),lineAgent.pos(),parent.pos(),pos());
if( intxn != null && !intxn.eq(parent.pos()) && !lineAgent.isColliding ){
isColliding = true;
return;
}
}
}
}
}
}
}
void update(){
if( isColliding ){
del();
}
else{
if(time()==0 && alive()){
if(parent!=null && parent.alive()){
ISpringLine ln = new ISpringLine(this, parent,100);
double t = -cos(IG.time()*0.015)*0.5+0.5;
ln.hsb( 0.7-t*0.2, 1, 0.8-t*0.2, 0.5); // color by time
if(parent.parent!=null && parent.parent.alive()){
IStraightenerCurve st =
new IStraightenerCurve(this,parent,parent.parent).tension(100);
st.hsb( 0.7-t*0.2, 1, 0.8-t*0.2, 0.5);
}
}
}
if(time()==4){
IVec dir2 = dir.cp();
double angle = PI*0.12 ;
if( IRand.pct(50) ){
dir.rot(angle);
dir2.rot(-angle);
}
else{
dir.rot(-angle);
dir2.rot(angle);
}
new LineAgent(this, dir);
if( IRand.pct(20) ){ // 20% branching probability
new LineAgent(this,dir2);
}
}
}
}
}
ばね力による近傍のエージェントの結束
![]()
![]()
![]()
import igeo.*;
import processing.opengl.*;
void setup(){
size(480,360,IG.GL);
for(int i=0; i < 4; i++){
new LineAgent(new IParticle(IRand.pt(-40,-40,0,40,40,0)).hide().fric(0.2), IRand.dir(IG.zaxis).len(2), null);
}
for(int i=0; i < 20; i++){
new IAttractor(IRand.pt(-200,-200,0,200,200,0)).linear(50).intensity(-30); //repulsion force
}
IG.bg(1.0,1.0,1.0);
IG.top();
}
class LineAgent extends IParticle{
LineAgent parent, root;
boolean isColliding;
IVec dir;
LineAgent(IParticle parent, IVec dir, LineAgent root){
super(parent.pos().cp(dir));
if(parent instanceof LineAgent){
this.parent = (LineAgent)parent;
}
isColliding=false;
hide(); // hide point
this.dir = dir;
fric(0.2);
if(root!=null){ this.root = root; }
else{ this.root = this; }
}
void interact(ArrayList< IDynamics > agents){
if(time()==0){ //only in the first time
for(int i=0; i < agents.size(); i++){
if(agents.get(i) instanceof LineAgent){
LineAgent lineAgent = (LineAgent)agents.get(i);
if(lineAgent!=this){ //agents include "this"
if(lineAgent.parent!=null && lineAgent.pos().dist(pos()) < pos().dist(parent.pos())*2){
IVec intxn = IVec.intersectSegment(lineAgent.parent.pos(),lineAgent.pos(),parent.pos(),pos());
if( intxn != null && !intxn.eq(parent.pos()) && !lineAgent.isColliding ){
isColliding = true;
return;
}
}
}
}
}
}
else if(time()==1){
for(int i=0; i < agents.size(); i++){
if(agents.get(i) instanceof LineAgent){
LineAgent lineAgent = (LineAgent)agents.get(i);
if(lineAgent!=this && lineAgent.alive()){ //agents include "this"
if(lineAgent.root != root){ // different branch
IVec dif = lineAgent.pos().dif(pos());
if(dif.len() < dir.len()*2.5 && dif.len()>dir.len()){ // within threshold
ISpringLine sp =
new ISpringLine(lineAgent,this,5,dir.len()*1.5).tension(5);
double t = -cos(IG.time()*0.015)*0.5+0.5;
sp.hsb(0.7-t*0.2, 1, 0.8-t*0.2, 0.2);
}
}
}
}
}
}
}
void update(){
if( isColliding ){
del();
}
else{
if(time()==0 && alive()){
if(parent!=null && parent.alive()){
ISpringLine ln = new ISpringLine(this, parent,100);
double t = -cos(IG.time()*0.015)*0.5+0.5;
ln.hsb( 0.7-t*0.2, 1, 0.8-t*0.2, 0.2); // color by tim
if(parent.parent!=null && parent.parent.alive()){
IStraightenerCurve st
= new IStraightenerCurve(this,parent,parent.parent).tension(100);
st.hsb( 0.7-t*0.2, 1, 0.8-t*0.2, 0.2);
}
}
}
if(time()==4){
IVec dir2 = dir.cp();
double angle = PI*0.12 ;
if( IRand.pct(50) ){
dir.rot(angle);
dir2.rot(-angle);
}
else{
dir.rot(-angle);
dir2.rot(angle);
}
new LineAgent(this, dir, root);
if( IRand.pct(20) ){ // 20% branching probability
new LineAgent(this,dir2, null);
}
}
}
}
}
力の場の適用
![]()
![]()
![]()
import igeo.*;
import processing.opengl.*;
void setup(){
size(480,360,IG.GL);
for(int i=0; i < 4; i++){
new LineAgent(new IParticle(IRand.pt(-40,-40,0,40,40,0)).hide().fric(0.2), IRand.dir(IG.zaxis).len(2), null);
}
for(int i=0; i < 20; i++){
new IAttractor(IRand.pt(-200,-200,0,200,200,0)).linear(50).intensity(-30);//repulsion force
}
new IPointCurlField(new IVec(0,0,0), new IVec(0,0,1)).intensity(50); //spinning force
IG.bg(1.0,1.0,1.0);
IG.top();
}
class LineAgent extends IParticle{
LineAgent parent, root;
boolean isColliding;
IVec dir;
LineAgent(IParticle parent, IVec dir, LineAgent root){
super(parent.pos().cp(dir));
if(parent instanceof LineAgent){
this.parent = (LineAgent)parent;
}
isColliding=false;
hide(); // hide point
this.dir = dir;
fric(0.2);
if(root!=null){ this.root = root; }
else{ this.root = this; }
}
void interact(ArrayList< IDynamics > agents){
if(time()==0){ //only in the first time
for(int i=0; i < agents.size(); i++){
if(agents.get(i) instanceof LineAgent){
LineAgent lineAgent = (LineAgent)agents.get(i);
if(lineAgent!=this){ //agents include "this"
if(lineAgent.parent!=null && lineAgent.pos().dist(pos()) < pos().dist(parent.pos())*2){
IVec intxn = IVec.intersectSegment(lineAgent.parent.pos(),lineAgent.pos(),parent.pos(),pos());
if( intxn != null && !intxn.eq(parent.pos()) && !lineAgent.isColliding ){
isColliding = true;
return;
}
}
}
}
}
}
else if(time()==1){
for(int i=0; i < agents.size(); i++){
if(agents.get(i) instanceof LineAgent){
LineAgent lineAgent = (LineAgent)agents.get(i);
if(lineAgent!=this && lineAgent.alive()){ //agents include "this"
if(lineAgent.root != root){ // different branch
IVec dif = lineAgent.pos().dif(pos());
if(dif.len() < dir.len()*2.5 && dif.len()>dir.len()){ // within threshold
ISpringLine sp =
new ISpringLine(lineAgent,this,5,dir.len()*1.5).tension(5);
double t = -cos(IG.time()*0.015)*0.5+0.5;
sp.hsb(0.7-t*0.2, 1, 0.8-t*0.2, 0.2);
}
}
}
}
}
}
}
void update(){
if( isColliding ){
del();
}
else{
if(time()==0 && alive()){
if(parent!=null && parent.alive()){
ISpringLine ln = new ISpringLine(this, parent,100);
double t = -cos(IG.time()*0.015)*0.5+0.5;
ln.hsb( 0.7-t*0.2, 1, 0.8-t*0.2, 0.2); // color by tim
if(parent.parent!=null && parent.parent.alive()){
IStraightenerCurve st
= new IStraightenerCurve(this,parent,parent.parent).tension(100);
st.hsb( 0.7-t*0.2, 1, 0.8-t*0.2, 0.2);
}
}
}
if(time()==4){
IVec dir2 = dir.cp();
double angle = PI*0.12 ;
if( IRand.pct(50) ){
dir.rot(angle);
dir2.rot(-angle);
}
else{
dir.rot(-angle);
dir2.rot(angle);
}
new LineAgent(this, dir, root);
if( IRand.pct(20) ){ // 20% branching probability
new LineAgent(this,dir2, null);
}
}
}
}
}
HOME
FOR PROCESSING
DOWNLOAD
DOCUMENTS
TUTORIALS (Java /
Python)
GALLERY
SOURCE CODE(GitHub)
PRIVACY POLICY
ABOUT/CONTACT