2016-01-11 6 views
1

Я хочу нарисовать пирог с треугольником в середине среза пиццика. На данный момент я рисую piechat с срезами и треугольниками в середине срезов, но треугольники не находятся под прямым углом. Мне нужно знать, как правильно расположить треугольники. Мой код и результат:Рисовать PieChart с треугольником в середине кусочка PieChart

import java.awt.*; 
import java.awt.geom.Ellipse2D; 
import javax.swing.*; 

class Slice { 

    double value; 
    Color color; 
    public Slice(double value, Color color) { 
     this.value = value; 
     this.color = color; 
    } 
} 

class PieChart extends JPanel { 

    private Color a = Color.RED; 
    private Color b = Color.BLUE; 
    private Color c = Color.YELLOW; 
    Slice[] slices = { 
       new Slice(60, a), 
       new Slice(100, b), 
       new Slice(200, c) 
    }; 

    public PieChart(){ 

    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     Graphics2D g2d = (Graphics2D)g; 
     super.paintComponent(g2d); 
     this.setBackground(new Color(255,255,255)); 

     g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 

     double total = 0.0D; 
     for (int i = 0; i < slices.length; i++) { 
      total += slices[i].value; 
     } 

     double curValue = 90.0D; 
     int startAngle = 0; 

     for (int i = 0; i < slices.length; i++) { 
      startAngle = (int) (curValue * 360/total); 
      int arcAngle = (int) (slices[i].value * 360/total); 
      g2d.setColor(slices[i].color); 
      g2d.fillArc(20, 20, 200, 200, startAngle, arcAngle); 

      g2d.setPaint(Color.BLACK); 
      int x = (int)(110+100*Math.cos(((-(startAngle+(arcAngle/2)))*Math.PI)/180)); 
      int y = (int)(110+100*Math.sin(((-(startAngle+(arcAngle/2)))*Math.PI)/180)); 

      Polygon p = new Polygon(new int[] {x, x+14, x+7}, new int[] {y, y, y-14}, 3); // this values seems to be important 
      g2d.draw(p); 
      g2d.fill(p); 

      curValue += slices[i].value; 
     } 
    } 
} 

enter image description here

Edit: должна выглядеть следующим образом:

enter image description here

+2

Было бы хорошо, чтобы увидеть картинку с * желаемыми * позиций треугольников. Сейчас не совсем понятно, чего вы хотите достичь. – Andremoniy

+2

@Andemoniy - Done – Linda

+0

Если я правильно это вижу, вы хотите, чтобы база треугольника касалась центральной точки дуги сектора. Они коснутся одной точки. Это верно? – user1803551

ответ

2

Я сделал первую дугу, чтобы начать с 0 часов (I th чернила, которые вы хотели сделать).

Поскольку вы используете fillArc, который принимает int с, округленное вниз double s может не добавить до полной суммы, и вы будете иметь зазоры между срезами:

enter image description here

Вместо этого используйте Arc2D.Double для получить более высокую точность:

enter image description here

class Slice { 

    double value; 
    Color color; 

    public Slice(double value, Color color) { 

     this.value = value; 
     this.color = color; 
    } 

    public Color getColor() { 

     return color; 
    } 

    public double getValue() { 

     return value; 
    } 
} 

class PieChart extends JPanel { 

    private final int SIZE = 500, START = 40, START_DEG = 90; 
    private final int TRIG_HBASE = 66, TRIG_HEIGHT = 36; 
    private final int x0 =(START + SIZE/2), y0 = START; 
    private final Polygon poly; 

    private Color a = Color.RED; 
    private Color b = Color.BLUE; 
    private Color c = Color.YELLOW; 
    Slice[] slices = {new Slice(65, a), new Slice(123, b), new Slice(212, c)}; 

    PieChart() { 

     setBackground(Color.WHITE); 

     int x1 = x0 + TRIG_HBASE, y1 = y0; 
     int x2 = x0 - TRIG_HBASE, y2 = y0; 
     int x3 = x0,    y3 = y0 - TRIG_HEIGHT; 
     poly = new Polygon(new int[] {x1, x2, x3}, new int[] {y1, y2, y3}, 3); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 

     Graphics2D g2d = (Graphics2D) g; 
     super.paintComponent(g2d); 

     g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 

     g2d.setColor(Color.LIGHT_GRAY); 
     g2d.fillRect(START, START, SIZE, SIZE); 

     double total = 0d; 
     for (Slice slice : slices) { 
      total += slice.getValue(); 
     } 

     double startAngle = START_DEG; 
     double arcAngle, centerAngle; 
     double x, y; 

     for (Slice slice : slices) { 
      arcAngle = (slice.getValue() * 360/total); 
      g2d.setColor(slice.getColor()); 
      g2d.fill(new Arc2D.Double(START, START, SIZE, SIZE, startAngle, arcAngle, Arc2D.PIE)); 

      centerAngle = Math.toRadians(((startAngle - START_DEG) + arcAngle/2)); 
      x = (START + SIZE/2 * (1 - Math.sin(centerAngle))); 
      y = (START + SIZE/2 * (1 - Math.cos(centerAngle))); 

      AffineTransform trans = AffineTransform.getTranslateInstance(x - x0, y - y0); 
      AffineTransform rot = AffineTransform.getRotateInstance(-centerAngle, x, y); 
      Shape s = trans.createTransformedShape(poly); 
      s = rot.createTransformedShape(s); 

      g2d.setColor(slice.getColor().darker()); 
      g2d.fill(s); 

      startAngle += arcAngle; 
     } 
    } 

    @Override 
    public Dimension getPreferredSize() { 

     return new Dimension(START * 2 + SIZE, START * 2 + SIZE); 
    } 
} 

poly служит в качестве основного треугольника и обращен вверх, основанием которого является точка 0 часов. Каждая дуга преобразует (преобразует) этот многоугольник так, чтобы его основание центрировалось в центре длины дуги и чтобы оно указывало наружу.

Примечания:

  • Не называйте setBackgroundpaintComponent внутри, назовем его пределами. Это заставляет механизм рисования автоматически рисовать фон при каждой перерисовке. Если вы положите его внутри, вы просто переопределяете инструкцию с каждой перекрашиванием. Кроме того, вы можете использовать g.clearRect для установки фона на белый (или fillRect для другого цвета).
  • Переустановите метод на панели, чтобы быть совместимым с его содержимым.
  • Работа с константами (final) вместо внутренних номеров. Таким образом, вам нужно только изменить их в одном месте, и все зависимости учитываются.
  • Нарезка может использовать методы геттера (как правило, предпочтительнее прямого доступа к полю), а также позволяет for each петель.
  • Работайте с double s и только конвертируйте в int в последнюю очередь, в противном случае вы теряете точность (вы преобразуете свои углы в int, а затем используйте их как аргумент double).
  • Math.toRadians и Math.toDegrees - предмет, которым нужно быть знаком.
  • Я сделал треугольники широко, чтобы показать, как они пересекаются с дугами, измените константы TRIG, чтобы поиграть с их размерами.Я также покрасил их, чтобы узнать, какой треугольник принадлежит той дуге.
  • Я добавил фона к дугам, чтобы лучше видеть периметр.

Вот результат с параметрами (и нет специальной окраски):

private final int SIZE = 200, START = 20, START_DEG = 90; 
private final int TRIG_HBASE = 7, TRIG_HEIGHT = 14; 

enter image description here

+1

очень очень отзывчивый ответ и большое спасибо за предоставленные советы! Как стартер Java это лучший способ получить ответ! – Linda

+0

Редактировать: есть ли причина, по которой конструктор должен быть установлен как «нет публичного»? – Linda

+1

@ Linda Нет, я просто добавил код в пустой конструктор, который вы указали в своем коде. См. Мой профиль для моей политики ответов, видимость - это то, что вам нужно установить в соответствии с большей картинкой, фрагмент кода не может сказать нам, что лучше. – user1803551

1

Здесь я сделал решение (изменить алгоритм немного):

public class Chart { 
public static void main(String[] args) { 
    JFrame frame= new JFrame(); 
    frame.add(new PieChart()); 
    frame.setSize(new Dimension(400, 400)); 
    frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 
    EventQueue.invokeLater(() ->{ 
     frame.setVisible(true); 
    }); 
} 

public static class Slice { 
    double value; 
    Color color; 

    public Slice(double value, Color color) { 
     this.value = value; 
     this.color = color; 
    } 
} 

public static class PieChart extends JPanel { 

    private static final long serialVersionUID = 1L; 
    private Color a = Color.RED; 
    private Color b = Color.BLUE; 
    private Color c = Color.YELLOW; 
    Slice[] slices = { new Slice(60, a), new Slice(100, b), 
      new Slice(200, c) }; 

    public PieChart() { 

    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     Graphics2D g2d = (Graphics2D) g; 
     super.paintComponent(g2d); 

     this.setBackground(Color.WHITE); 
     g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON); 

     int upperLeftX = 20; 
     int upperLeftY = 20; 
     int r = 100; 
     int startAngle = 0; 


     double curValue = 0.0; 

     for (int i = 0; i < slices.length; i++) { 
      startAngle = (int) curValue ; 
      int arcAngle = (int) slices[i].value ; 
      g2d.setColor(slices[i].color); 
      g2d.fillArc(upperLeftX, upperLeftY, r*2, r*2, startAngle, arcAngle); 

      g2d.setPaint(Color.BLACK); 

      double qi = curValue+slices[i].value/2; 

      int x = upperLeftX + r + (int)(Math.cos(qi*Math.PI/180)*r); 
      int y = upperLeftY + r - (int)(Math.sin(qi*Math.PI/180)*r); 
      //point touching the circle (x,y)->half point of the base    
      int x1 = x - (int)(7*Math.sin(qi*Math.PI/180)); 
      int y1 = y - (int)(7*Math.cos(qi*Math.PI/180)); 

      int x2 = x + (int)(7*Math.sin(qi*Math.PI/180)); 
      int y2 = y + (int)(7*Math.cos(qi*Math.PI/180)); 

      int x3 = upperLeftX + r + (int)(Math.cos(qi*Math.PI/180)*(r+12)); 
      int y3 = upperLeftY + r - (int)(Math.sin(qi*Math.PI/180)*(r+12)); 


      Polygon p = new Polygon(new int[] { x1, x2, x3 }, 
        new int[] { y1, y2, y3 }, 3); // this values seems to 
                // be important 

      g2d.draw(p); 
      g2d.fill(p); 

      curValue += slices[i].value; 
     } 
    } 
} 
} 
+0

Это не работает, если я изменяю размеры срезов, например. '{63, 112, 212}'. И с '{60, 70, 80}' дуги не заполняют круговую диаграмму. – user1803551

+0

Общий совет: когда вы говорите что-то вроде «* измените алгоритм немного», вы захотите объяснить, что вы сделали, иначе это не ответ так сильно, как «здесь, есть какой-то код», даже если решение префект. – user1803551

+0

Совет отметил :). Со значениями: 63,112,212 сумма значений составляет более 360, поэтому она кажется (из них фактически позиционируется только желтая часть, нарисованная над красным). В другом случае сумма меньше 360, и поэтому арка не заполнена полностью. Я не прикасался к части логической схемы, а затем извлекал значения в переменные, поскольку вопрос касался позиционирования треугольника. –