Среда программирования:
Eclipce
Статья по теме:
Программа строит фрактальные деревья по заданным параметрам.
- Поля Х и Y отвечают за позицию центра на экране.
- Поле Distance отвечает за дистанцию корня дерева от центра.
- Поле Number отвечает за количество деревьев, растущих вокруг центра.
- Поле Rotation отвечает за поворот деревьев относительно позиции дерева.
- В третьем столбике находится спиннер, которым задаётся количество поддеревьев.
- В четвёртом столбике в выпадающем меню выбирается параметры какой ветви будут изменяться слайдерами.
- Слайдеры изменяют соответствующий параметр ветви.
Фрактальное дерево в данной программе рисуется рекурсивно, отдельно от вычисления координат вершин ветвей.
Код программы:
package canvas; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; @SuppressWarnings("serial") public class Fractal extends JFrame{ /* * JSlider - три слайдера, настраивающие изменение дерева, в процессе рисования * s - Строка для выпадающего меню * jchoose - выпадающее меню * JTextField - поля для ввода информациио позиции прсиа дерева * Canvas - место в окне, выделенное под рисование дерева * */ JSlider decrease=new JSlider(),turn=new JSlider(),start_len=new JSlider(); String s[]={"0","1","2"}; JComboBox<String> jchoose=new JComboBox<String>(s); JSpinner how_branches=new JSpinner(); JTextField coordX= new JTextField(3), coordY= new JTextField(3), distance_from_center= new JTextField(3), rotate_by_round= new JTextField(3), number_of_roots= new JTextField(3) ; Canvas canvas=new Canvas(); boolean isDone = false, is_set_sliders=false; /* * Метод, создающий окно и расставляющий элементы на нём * В данном методе указывается поведение объектов, * при взаимодействии пользователя с ними * */ Fractal(){ /* * Для более гибкой расстановки элементов используются панели элементов * */ JPanel se=new JPanel(), coords=new JPanel(), X=new JPanel(), Y=new JPanel(), pos_by_canv_center=new JPanel(), dist=new JPanel(), num=new JPanel(), rot=new JPanel(), slide_panel=new JPanel(), slide_start=new JPanel(), slide_dec=new JPanel(), slide_turn=new JPanel(); /* * Неизменяемый текст около полей. * Подсказки для полей ввода и слайдеров * */ JTextArea textX=new JTextArea("X"), textY=new JTextArea("Y"), textNum=new JTextArea("Number"), textDist=new JTextArea("Distance"), textRot=new JTextArea("Rotation"), text_start=new JTextArea("Длина корня"), text_dec=new JTextArea("Убывание длины ветви"), text_turn=new JTextArea("Поворот ветви"); /* * Слушающий класс, который будет вызывать * обновление полей при нажатии клавиш, * когда текстовое поле находится в фокусе * */ KeyListener checkWhenType=new KeyListener() { public void keyReleased(KeyEvent e) {changeToCorrect();canvas.repaint();} public void keyPressed(KeyEvent e) {changeToCorrect();canvas.repaint();} public void keyTyped(KeyEvent e) {changeToCorrect();canvas.repaint();} }; /* * Слушающий класс, вызывающий обновление * дерева при сдвиге слайдера * */ ChangeListener chekWhenSlide=new ChangeListener() { public void stateChanged(ChangeEvent e) { changeToCorrect(); canvas.reload(); canvas.repaint(); } }; /* * Слушающий класс, вызывающий обноелние * при выборе числа из выпадающего списка * */ ActionListener chooseListener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { is_set_sliders=true; if(jchoose.getSelectedIndex() <0 )return; start_len.setValue(canvas.len); turn.setValue((int)(canvas.rb[jchoose.getSelectedIndex()]*100f) ); decrease.setValue( (int)(canvas.ld[jchoose.getSelectedIndex()]*100f) ); is_set_sliders=false; } }; /* Определяет расположение обьектов в окне*/ setLayout(new BorderLayout(1,1)); /* Layout manager-ы будут определять расположение групп обьектов*/ pos_by_canv_center.setLayout(new BoxLayout(pos_by_canv_center, BoxLayout.Y_AXIS)); slide_panel.setLayout(new BoxLayout(slide_panel, BoxLayout.Y_AXIS)); coords.setLayout(new BoxLayout(coords, BoxLayout.Y_AXIS)); slide_start.setLayout(new FlowLayout(0)); slide_turn.setLayout(new FlowLayout(0)); slide_dec.setLayout(new FlowLayout(0)); dist.setLayout(new FlowLayout(0)); num.setLayout(new FlowLayout(0)); rot.setLayout(new FlowLayout(0)); se.setLayout(new FlowLayout(0)); X.setLayout(new FlowLayout(0)); Y.setLayout(new FlowLayout(0)); /* Добавление обработчика событий к объектам */ distance_from_center.addKeyListener(checkWhenType); number_of_roots.addKeyListener(checkWhenType); rotate_by_round.addKeyListener(checkWhenType); start_len.addChangeListener(chekWhenSlide); jchoose.addActionListener(chooseListener); decrease.addChangeListener(chekWhenSlide); turn.addChangeListener(chekWhenSlide); coordX.addKeyListener(checkWhenType); coordY.addKeyListener(checkWhenType); how_branches.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent arg0) { int val=how_branches.getValue().hashCode(); System.out.println(val); if(val<1)how_branches.setValue(1); changeToCorrect(); canvas.reload(); //canvas.repaint(); } }); /* Всплывающие подсказки текстовых полей*/ rotate_by_round.setToolTipText("Наклон относительно окружности"); distance_from_center.setToolTipText("Расстояние от центра"); number_of_roots.setToolTipText("Количество деревьев"); coordX.setToolTipText("Позиция по X"); coordY.setToolTipText("Позиция по Y"); /* Цвет рамки текстовых полей */ distance_from_center.setBorder(BorderFactory.createLineBorder(Color.blue, 3, true)); number_of_roots.setBorder(BorderFactory.createLineBorder(Color.blue, 3, true)); rotate_by_round.setBorder(BorderFactory.createLineBorder(Color.blue, 3, true)); coordX.setBorder(BorderFactory.createLineBorder(Color.green, 2, true)); coordY.setBorder(BorderFactory.createLineBorder(Color.green, 2, true)); /* Настройка значений обектов в значения по-умолчанию */ decrease.setValue((int)(canvas.ld[0]*100.0)); coordX.setText(Integer.toString(canvas.x)); coordY.setText(Integer.toString(canvas.y)); turn.setValue((int)(canvas.rb[0]*100.0)); distance_from_center.setText("0"); rotate_by_round.setText("0.0"); number_of_roots.setText("1"); how_branches.setValue(3); start_len.setValue(200); /* Настройки максимального значения для слайдеров*/ start_len.setMaximum(1000); decrease.setMaximum(95); turn.setMaximum(628); /* Поля с подсказками для обьектов * Настройка видимости фона * и возможности ввода в них */ text_start.setEditable(false); text_turn.setEditable(false); textDist.setEditable(false); text_dec.setEditable(false); text_start.setOpaque(false); textRot.setEditable(false); textNum.setEditable(false); text_turn.setOpaque(false); textDist.setOpaque(false); text_dec.setOpaque(false); textX.setEditable(false); textY.setEditable(false); textNum.setOpaque(false); textRot.setOpaque(false); textX.setOpaque(false); textY.setOpaque(false); se.setOpaque(true); /* Обьединение обьектов в группы и добавление их в окно */ dist.add(distance_from_center); pos_by_canv_center.add(dist); pos_by_canv_center.add(num); pos_by_canv_center.add(rot); slide_panel.add(slide_start); slide_panel.add(slide_turn); slide_panel.add(slide_dec); slide_start.add(start_len); slide_dec.add(decrease); slide_turn.add(turn); slide_dec.add(text_dec); slide_turn.add(text_turn); slide_start.add(text_start); num.add(number_of_roots); rot.add(rotate_by_round); num.add(textNum); rot.add(textRot); dist.add(textDist); X.add(coordX); Y.add(coordY); coords.add(X); coords.add(Y); X.add(textX); Y.add(textY); se.add(coords); se.add(pos_by_canv_center); se.add(how_branches); se.add(jchoose); se.add(slide_panel); /* Добавляет в окно в центр холст и к нижней части окна*/ add(canvas,BorderLayout.CENTER); add(se,BorderLayout.SOUTH); isDone=true; setSize(1100,600); setDefaultCloseOperation(3); setVisible(true); } /* * Метод, проверяющий правильность ввода в поля, во время ввода * В некоторых случаях может не давать стереть последнюю цифру * */ void changeToCorrect(){ if(!isDone)return; if(is_set_sliders)return; /* Проверка сдвига центра холста */ if(coordX.getText().matches("\\d+")) canvas.x=Integer.parseInt(coordX.getText()); else coordX.setText(canvas.x+""); if(coordY.getText().matches("\\d+")) canvas.y=Integer.parseInt(coordY.getText()); else coordY.setText(canvas.y+""); /* Проверка изменения относительно центра */ if(distance_from_center.getText().matches("\\d+")) canvas.lfromCenter=Integer.parseInt(distance_from_center.getText()); else distance_from_center.setText(canvas.lfromCenter+""); if(rotate_by_round.getText().matches("\\d+\\.?\\d*")) if(canvas.rotC == Double.valueOf( rotate_by_round.getText())); else canvas.rotC=Double.valueOf(rotate_by_round.getText()); else rotate_by_round.setText(String.valueOf(canvas.rotC)); if(number_of_roots.getText().matches("\\d+"))canvas.count=Integer.parseInt(number_of_roots.getText()); else number_of_roots.setText(canvas.count+""); canvas.len=start_len.getValue(); /* Настройки ветвей */ int var=how_branches.getValue().hashCode(); int indexVar=jchoose.getSelectedIndex(); if(indexVar>=0 && indexVar < canvas.ld.length){ canvas.ld[indexVar]=decrease.getValue()/100.0; canvas.rb[indexVar]=turn.getValue()/100.0; } if(var != canvas.ld.length){ String str[]=new String[var]; jchoose.removeAllItems(); for(int i=0;i<var;i++){ str[i]=i+""; jchoose.addItem(str[i]); } jchoose.setSelectedIndex(0); boolean is_gt=(var>canvas.ld.length); double ld[]=new double[var], rb[]=new double[var]; for(int i=0; ( i< var && !is_gt) || (i < canvas.ld.length && is_gt); i++){ ld[i]=canvas.ld[i]; rb[i]=canvas.rb[i]; } if(is_gt){ for(int i=canvas.ld.length;i<var;i++){ ld[i]=Math.random()*0.5+0.1; rb[i]=Math.random()*6; } } canvas.ld=ld; canvas.rb=rb; canvas.countBranches=var; repaint(); } } public static void main(String[] args) { new Fractal(); } } /* Класс, описывающий фрактальное дерево как множество корней*/ class Branch{ static final double M_PI=3.1415; static final int MAXBRANCHES=3; static final int MAXDEPH=100; static final double MAXROTATION=M_PI*2; static final double MAXLENDECREESE=1; static final int MINNUMOFBRANCHES=1; /* xpos, ypos -Координаты ветви в пространстве * length - Длина ветви * rotate - Поворот ветви * numOfBranches - количество ветвей у каждой ветки * next - Ветви, находящиеся глубже, относительно корня * len_Decr - Параметр убывания длины, на который изменяется i-тая ветка * br_Rot - Параметр кручения, на который изменяется i-тая ветка * */ int xpos; int ypos; int length; double rotate; static int numOfBranches; // 1 > Branch next[]=null; static double len_Decr[]; static double br_Rot[]; /* Функция создаёт дерево по заданным входным данным, * но не больше чем на 100 ветвей в глубину */ public Branch(int x, int y, double rotate, int len, int deph) { xpos=x; ypos=y; length=len; if(rotate<MAXROTATION && rotate>0)(this).rotate=rotate; else if(rotate < 0)(this).rotate=rotate+MAXROTATION; else (this).rotate=rotate-MAXROTATION; if(deph+1<MAXDEPH && len>2){ next=new Branch[len_Decr.length]; for(int i=0;i<len_Decr.length;i++){ next[i]=new Branch(getX2(),getY2(),br_Rot[i]+rotate,(int)(len*len_Decr[i]),deph+1); } } } /* Второй конструктор, в который передаются параметры для ветвей * Параметры ветвей записываются в статическую переменную и дальнейшие * параметры берутся уже из класса */ public Branch(int x, int y,double rotate,int len, double lenDecr[], double brRot[],int numOfBr, int deph){ br_Rot=brRot; len_Decr=lenDecr; xpos=x; ypos=y; length=len; if(rotate<MAXROTATION && rotate>0)(this).rotate=rotate; else if(rotate < 0)(this).rotate=rotate+MAXROTATION; else (this).rotate=rotate-MAXROTATION; if(deph+1<MAXDEPH && len>2){ next=new Branch[len_Decr.length]; for(int i=0;i<len_Decr.length;i++){ next[i]=new Branch(getX2(),getY2(),br_Rot[i]+rotate,(int) (len*len_Decr[i]),deph+1); } } } int getX2(){ return (int)(xpos+length*Math.cos(rotate)); } int getY2(){ return (int)(ypos+length*Math.sin(rotate)); } /* Рисует дерево по уже заданным параметрам. */ void draw(Graphics g){ Graphics2D g2=(Graphics2D)g; g2.drawLine(xpos, ypos, getX2(), getY2()); if(next!=null) for(int i=0;i<next.length;i++){ if(next[i]!=null) next[i].draw(g); } } } /* олст для рисования дерева */ @SuppressWarnings("serial") class Canvas extends JComponent{ int x=200; int y=200; double rot=0; int len=200; int lfromCenter=0; double rotC=0; int count =1; Branch root; int countBranches=3; double ld[]={0.5,0.4,0.2}; double rb[]={-0.7,0.5,0.3}; /* При создании холста создаётся дерево*/ Canvas(){ root=new Branch(0, 0, 0, 200,ld,rb,3,55); } /* Создаёт новое дерево, поновым характеристикам */ void reload(){ root=new Branch(0, 0, rot, len,ld,rb,countBranches,0); } /* Прорисовка холста */ public void paintComponent(Graphics g){ paintComponents(g); Graphics2D g2d=(Graphics2D)g; g2d.setPaint(new Color(1f,0,1f)); g2d.translate(x, y); /* Рисование n деревьев со сдвигом и поворотом холста. * В итоге холст назодится в исходном положении */ for(double i=0;i<6.28;i+=6.28/count){ g2d.rotate(i); g2d.translate(lfromCenter, 0); g2d.rotate(rotC); root.draw(g); g2d.rotate(-rotC); g2d.translate(-lfromCenter, 0); g2d.rotate(-i); } } }
Прикрепленный файл | Размер |
---|---|
fractalBuilder.zip | 13.91 кб |