Simplifying Graphics With Java and Threads

本文介绍了如何用Java结合线程简化图形算法来渲染复杂图形。代码中有三个线程:执行复杂计算的Renderer、定期唤醒绘图的Animator和响应用户事件的默认用户界面线程。还提到了使用离屏图形缓冲区和渐进式渲染,避免了类似Netscape的奇怪滚动效果。

Simplifying Graphics With Java and Threads

By Alex Chaffee and John Papageorge
July 1997

<!-- Begin Main Body Text -->

Here's some code that EarthWeb's Alex Chaffee likes to use as an example of how Java can be used to simplify algorithms by combining graphics with threading to render complex graphics.

Basically there are three threads: a Renderer, which performs a complex calculation; an Animator, which wakes up periodically and draws the current image to the screen; and of course the default User Interface thread, which responds to user events and changes the display as appropriate.

The Renderer runs at a low priority—just grinding away forever, or at least until it's done; it shouldn't interfere with the other two threads. The Animator only comes to life every 500 msec or so, to avoid the expense of drawing each pixel.

To perform a specific calculation, subclass the Renderer to make a Mandelbrot function. Note the object-oriented design: this way, the Mandelbrot subclass only needs to override the Run method and doesn't have to worry about the threading implementation, which is handled by its superclass. Of course, in this example, the threading implementation is trivial, but this is a teaching exercise.

Other items of note are the use of an offscreen Graphics buffer, and the use of progressive rendering. The code makes several rough passes over the image, calculating the value in each quadrant, then gradually refines the view. Unlike Netscape's rendering of progressive gifs, this program treats a calculated pixel as the "center" of a square of color, not as the top corner or a pixel-wide stripe, and so avoids that odd venetian-blind scrolling-up effect. With a laugh, Chaffee says, "But maybe I'm the only one in the world who thought Netscape's gif-rendering algorithm looked funny." now , see Chaffee's source code

/*
        man.java

        a test to do threaded animation

        Copyright (c) 1996 Alex Chaffee, all rights reserved
        Permission is granted to use this source code for
        instructional purposes as long as copyright information
        remains intact.

        @Author:        Alex Chaffee

*/

import java.awt.*;
import java.util.*;
import java.applet.*;
import java.lang.Math;

/**
 *      Animator

 * This class implements the thread that draws the image to the screen
 * every 500 msec.

 * @author Alex Chaffee

 **/

class Animator implements Runnable {

  static int delay = 500;

  private Applet applet;
  private Vector images;
  private Thread thread = null;
  private int frame;

  public Animator(Applet appletIn, Vector imagesIn) {
    applet = appletIn;
    images = imagesIn;
  }

  public void start() {
    if (thread == null) {
      thread = new Thread(this);
      thread.start();
    }
  }

  public void stop() {
    System.out.println("Animator stopped");
    thread.stop();
    thread = null;
  }
 public void run() {
    thread.setPriority(Thread.MAX_PRIORITY-1);
    while (thread != null) {
      applet.repaint();
      try {
        thread.sleep(delay);
      } catch (InterruptedException e) {};

      // Increment frame

      // Must use synchronized on the off chance that update gets called
      // between the frame++ and the frame=0

      synchronized (this) {
        frame++;
        if (frame > images.size()) {
          frame = 0;
        }
      }

    }
  }

  public void paint(Graphics g) {
    if (frame < images.size()) {
      Image image = (Image)images.elementAt(frame);
      if (image != null) {
        g.drawImage(image, 0, 0, null); // try it without an ImageObserver
      }
    }
  }
}

/**
 *      Renderer
 * This class progressively renders the image
 **/

class Renderer implements Runnable {

  protected Image image;
  protected Thread thread = null;
  protected int delay = 50;
  static int count = 0;

  public Renderer(Image imageIn) {
    image = imageIn;
  }

  public void start() {
    if (thread == null) {
      thread = new Thread(this, "Renderer " + count++);
      thread.setPriority(Thread.MIN_PRIORITY+1);
      thread.start();
    }
  }

  public void stop() {
    System.out.println("Renderer stopped");
    thread.stop();
    thread = null;
  }

  public void setDelay(int delay) {
    this.delay = delay;
  }

  public void run() {}

}

/**
  Subclasses Renderer in order to implement a Mandelbrot function
**/

class Mandelbrot extends Renderer {

  /**
   * zoom constant
   */
  protected static float kZoom = (float)1.3;

  /**
   * Magnification of the image -- mag 0 = full span of 4 (-2 to +2)
   * <tt>span = 4 / (K^mag)</tt>
   * @see kZoom
   */
  int mag;

  /**
   * point in virtual space around which we're drawing the thing
   * (i.e. where in virtual space is (0,0) in the window
   */
  float originX = 0;
  float originY = 0;

  public Mandelbrot(Image image, int mag, float originX, float originY) {
    super(image);
    this.mag = mag;
    this.originX = originX;
    this.originY = originY;
  }

  static float MagToSpan(int mag) {
    return 4 / (float)(java.lang.Math.pow(kZoom, mag));
  }

  /**
   * Render this image progressively.
   */
 public void run() {

    /**
      * The graphics port of the image we're drawing to
      */
    Graphics g;
    g = image.getGraphics();

    int width, height;
    width = image.getWidth(null);
    height = image.getHeight(null);

    /**
      * The width of the window on the virtual space
      * @see mag
      */
    float span = MagToSpan(mag);

    /**
     * current resolution (how big each pixel is)
     */
    int resolution;

    /**
     * how far in do we go before we're rendering by pixel
     */
    int resolutionMax = 10;     // should calculate based on image size

    /**
      * current increment (based on resolution)
      */
    float inc;

    resolution = 1;
    int widthPixel, heightPixel;
    do {

      // the resolution determines which power of two we're dividing
      // the span by -- so it fills in by squares
      float scale = 1 /  (float)(java.lang.Math.pow(2, resolution));
      inc = span * scale;

      // pre-calculate the width and height of each "pixel" in the image
      widthPixel = (int)(scale * width) + 1;
      heightPixel = (int)(scale * height) + 1;

      spew("resolution " + resolution + " pixel=(" + widthPixel + ", " +
heightPixel + ")");

      // Mandelbrot function
      Color c;
      int maxiterations = 100;
      int i;
      float temp, r, x, y;
    float minX = originX + inc/2;
      float maxX = originX + span;
      float minY = originY + inc/2;
      float maxY = originY + span;

      for (float c1= minX; c1 < maxX; c1 += inc) {
        for (float c2 = minY; c2 < maxY; c2 += inc) {

          // Nitty gritty, merci Benoit
          r = 0;
          x = 0;
          y = 0;
          i = 0;

          while ((i<maxiterations) && (r<4)) {
            r = x*x + y*y;
            temp = x*x - y*y + c1;
            y = 2*x*y + c2;
            x = temp;
            i++;
          }

          // Now i is the level, so base color on it
          if (i == maxiterations) {
            c = Color.black;
          } else {

// All sorts of different color palettes -- we should parameterize this, eh?

//          c = new Color(i*2, i*i%256, 255 - (i*i));
//          c = new Color(i*2, i*i%256, 255 - (i*2));
            c = new Color(i*2, ((i*i)+128)%256, 255 - (i*2));
//          c = new Color(i*2, i, 255 - i*2);
//          System.out.println(i + ": " + c.toString());
          }

          // should optimize by incrementing screen pos rather than
          // recalculating
          int h = (int)(((c1 - originX)*width)/span);
          int v = (int)(((c2 - originY)*height)/span);

          // center on the point, not upper-left
          h -= widthPixel/2;
          v -= heightPixel/2;

          g.setColor(c);
          g.fillRect(h, v, widthPixel, heightPixel);

          Thread.currentThread().yield();

        }
 /*
        // even with yield, there's a goofy bug with Netscape 2.0b5
        // and lower wherein the browser never takes time for itself
        // (how selfless). So I'll try sleeping for a millisec just to
        // see if it helps

        Thread.currentThread().sleep(1);
*/
      } // for traverse virtual space
      resolution++;

    } while (widthPixel > 1 || heightPixel > 1);

    spew("stopped");

  } // method run

  void spew(String str) {
    System.out.println("(" + originX + "," + originY + ")x" + mag + ":" + str);
  }

  public  static int iterate(float c1, float c2) {

    int maxiterations = 100;

    // Nitty gritty, merci Benoit
    float r, x, y, temp;
    int i;
    r = 0;
    x = 0;
    y = 0;
    i = 0;

    while ((i<maxiterations) && (r<4)) {
      r = x*x + y*y;
      temp = x*x - y*y + c1;
      y = 2*x*y + c2;
      x = temp;
      i++;
    }

    return i;
  }
}
/**
 * man - the main applet class
 **/

public class man extends Applet {

  private int cImages = 1;
  private Vector images = null;
  private Vector renderers = null;
  private Animator animator = null;

  float originX = (float)-2.0;
  float originY = (float)-2.0;

  /**
    * magnification of the first frame in the list
    */
  int mag = 0;

  public void start() {

    // read the parameters
    String str;

//    System.out.println("originx " + getParameter("originx"));
//    System.out.println("originy " + getParameter("originy"));
//    System.out.println("mag " + getParameter("mag"));

    try {
      if ((str = getParameter("originx"))!=null)
        originX = new Float(str).floatValue();
      if ((str = getParameter("originy"))!=null)
        originY = new Float(str).floatValue();
      if ((str = getParameter("mag"))!=null)
        mag = new Integer(str).intValue();
    } catch (NumberFormatException e) {
      System.out.println("Number format exception!");
    }

    startThreads();

  }

  void startThreads() {

    // Fill the vector with blank images
    images = new Vector(cImages);
    for (int i=0; i<cImages; ++i) {
      Image image = createImage( size().width, size().height );
      images.addElement(image);
    }
    // start each rendering thread
    renderers = new Vector(cImages);
    for (int i=0; i<cImages; ++i) {
      Renderer renderer = new Mandelbrot((Image)images.elementAt(i), mag+i,
originX, originY);
      renderer.start();
      renderers.addElement(renderer);
    }

    // start the animator
    animator = new Animator(this, images);
    animator.start();

    // a repaint for good measure
    repaint();
  }

  public void stop() {
    stopThreads();
  }

  /**
   * stop all threads
   */

  public void stopThreads() {
    animator.stop();
    for (int i=0; i<cImages; ++i) {
      ((Renderer)renderers.elementAt(i)).stop();
    }
  }

  /* must override to reduce flicker */
  public void update(Graphics g) {
    paint(g);
  }

  public void paint(Graphics g) {
    animator.paint(g);
  }

  /* Events */
  public boolean keyDown(Event evt, int key) {

    switch(key) {
    case '+':
    case '=':
      // Zoom in
      zoom(mag+1);
      return true;
    case '-':
      // Zoom out
      if (mag>0)
        zoom(mag-1);
      return true;

    default:
      return false;
    } // switch
  } // keyDown

  void zoom(int magNew) {

    float spanOld = Mandelbrot.MagToSpan(mag);
    float centerX = originX + spanOld/2;
    float centerY = originY + spanOld/2;

    mag = magNew;

    float spanNew = Mandelbrot.MagToSpan(mag);
    originX = centerX - spanNew/2;
    originY = centerY - spanNew/2;

    stopThreads();
    startThreads();

  }


  public boolean mouseDown(Event evt, int x, int y) {
    System.out.println(evt.toString());

    stopThreads();
    animator = null;

    float span = Mandelbrot.MagToSpan(mag);
    originX = x * span / size().width + originX - span/2;
    originY = y * span / size().height + originY - span/2;

    System.out.println("New origin: " + x + (new Dimension(x,y)).toString()
+ " -> "
                       + originX + "," + originY );

    start();

    return true;
  }
 static float convert(int x, int width, int mag, float origin) {
    float span = Mandelbrot.MagToSpan(mag);
    float z = x * span/width + origin;
    return z;
  }

  public boolean mouseMove(Event evt, int x, int y) {

    float vx = convert(x, size().width, mag, originX);
    float vy = convert(y, size().height, mag, originY);
    int i = Mandelbrot.iterate(vx, vy);

    String str = "i=" + (new Integer(i)).toString();
    str = str + " (" + vx + ", " + vy + ")";
    getAppletContext().showStatus(str);

//    System.out.println((new Integer(i)).toString());

    return true;

  }

}
### One-Shot 架构搜索方法的理解与简化 One-shot架构搜索是一种高效的神经网络架构设计策略,旨在通过一次训练过程来评估多个候选模型结构。这种方法显著减少了传统NAS(Neural Architecture Search)所需的计算资源和时间成本。 #### 方法概述 在one-shot架构搜索中,构建了一个超网(Supernet),该超网包含了所有可能子网络的组合[^1]。这些子网络共享权重参数,在每次迭代过程中只更新部分连接权值而不是整个网络的所有参数。这使得能够在单次实验周期内完成大量不同配置下的性能测试。 为了进一步优化这一流程并降低复杂度: - **引入代理任务**:使用较小规模的数据集作为代理来进行快速验证,从而减少全面训练所需的时间开销。 - **基于梯度的信息传递机制**:利用反向传播算法有效地调整各层之间的依赖关系,确保即使是在大规模数据上也能保持高效性。 ```python class SuperNet(nn.Module): def __init__(self, num_layers=8): super().__init__() self.layers = nn.ModuleList([nn.Conv2d(3, 64, kernel_size=3)] + [nn.Linear(64, 64) for _ in range(num_layers)]) def forward(self, x, path_indices): outputs = [] for i, idx in enumerate(path_indices): output = F.relu(self.layers[i](x)) outputs.append(output) if not isinstance(idx, int): continue x = sum(outputs[j] * (idx==j).float() for j in range(i+1)) return x ``` 此代码片段展示了如何定义一个简单的超级网络类`SuperNet`,其中包含多条路径供选择。实际应用时会更加复杂,涉及更多类型的卷积操作和其他组件。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值