📄 mandelbrotdisplay.java
字号:
if (ct < 0) // Only -1 is possible, representing the Mandelbrot set. return 0; // RGB code for black else if (paletteLength == 0) return palette[ct]; else { ct = ct % paletteLength; return palette[ct]; } } /** * Applies current palette to the image, or to any part of the image * that has been completed, if a computation is in progress. */ synchronized private void recomputeColors() { if (OSC == null) return; if (palette == null) createPalette(); for (int i = 0; i < iterationCounts.length; i++) { if (iterationCounts[i] != null) { for (int j = 0; j < imageWidth; j++) rgb[j] = getColorForIterationCount(iterationCounts[i][j]); OSC.setRGB(0, i, imageWidth, 1, rgb, 0, imageWidth); } } repaint(); } /** * This is called to abort the current computation, if any. Note that this method * calls applyFinishedJobsToImage() to get the data from any outstanding finished * jobs and apply it to the image. */ synchronized private void stopComputing() { if (!computing || OSC == null) return; applyJobsToImageTimer.stop(); applyFinishedJobsToImage(); finishedJobs = null; computing = false; setStatus(STATUS_READY); } /** * This is called to start a new computation. * */ synchronized private void startComputing() { if (OSC == null) return; stopComputing(); Graphics g = OSC.getGraphics(); g.setColor(Color.LIGHT_GRAY); g.fillRect(0,0,getWidth(),getHeight()); g.dispose(); repaint(); int processCount = Runtime.getRuntime().availableProcessors(); if (workerThreads == null) { System.out.println("Creating " + processCount + " threads."); workerThreads = new ComputeThread[processCount]; int priority = Thread.currentThread().getPriority() - 1; for (int i = 0; i < processCount; i++) { workerThreads[i] = new ComputeThread(); try { // By setting the thread to be a "daemon" means that the // program can terminate even if this thread is still running. workerThreads[i].setDaemon(true); } catch (Exception e) { System.out.println("Can't set thread to daemaon."); } try { // By reducing the priority of the thread, we ensure that // the user interface thread will be responsive. Threads // of lower priority only run when no thread of higher // priority wants to run. workerThreads[i].setPriority(priority); } catch (Exception e) { System.out.println("Can't reduce worker thread priority?"); } workerThreads[i].start(); } } checkAspect(); computationNumber++; jobs = iterationCounts.length; jobsAssigned = 0; jobsCompleted = 0; computing = true; finishedJobs = new LinkedList<Job>(); for (int i = 0; i < iterationCounts.length; i++) iterationCounts[i] = null; notifyAll(); applyJobsToImageTimer.start(); setStatus(STATUS_WORKING); } /** * Adjusts the xy limits to fit the aspect ratio of the display. If the shape of * the requested region in the plane does not match the shape of the display, * then either the range of x values or the range of y values will be increased * to make the shapes match. Note that the full requested ranges are always shown. * There just might be some extra parts of the plane visible on the top and bottom * or sides. */ private void checkAspect() { xmin = xmin_requested; xmax = xmax_requested; if (xmax < xmin) { double temp = xmin; xmin = xmax; xmax = temp; } ymin = ymin_requested; ymax = ymax_requested; if (ymax < ymin) { double temp = ymax; ymax = ymin; ymin = temp; } double width = xmax - xmin; double height = ymax - ymin; double aspect = width/height; double windowAspect = (double)getWidth()/(double)getHeight(); if (aspect < windowAspect) { double newWidth = width*windowAspect/aspect; double center = (xmax + xmin)/2; xmax = center + newWidth/2; xmin = center - newWidth/2; } else if (aspect > windowAspect) { double newHeight = height*aspect/windowAspect; double center = (ymax+ymin)/2; ymax = center + newHeight/2; ymin = center - newHeight/2; } dx = (xmax - xmin) / (getWidth() - 1); dy = (ymax - ymin) / (getHeight() - 1); } /** * Builds the array that holds the palette colors, based on current settings. */ private void createPalette() { if (paletteLength == 0) palette = new int[maxIterations+1]; else palette = new int[paletteLength]; for (int i = 0; i < palette.length; i++) { float fraction = ((float)i)/(palette.length-1); Color color; switch (paletteType) { case PALETTE_GRADIENT: float r1 = gradientPaletteColor1.getRed()/255.0F; float r2 = gradientPaletteColor2.getRed()/255.0F; float r = Math.max(0,Math.min(1,r2*fraction + r1*(1-fraction))); float g1 = gradientPaletteColor1.getGreen()/255.0F; float g2 = gradientPaletteColor2.getGreen()/255.0F; float g = Math.max(0,Math.min(1,g2*fraction + g1*(1-fraction))); float b1 = gradientPaletteColor1.getBlue()/255.0F; float b2 = gradientPaletteColor2.getBlue()/255.0F; float b = Math.max(0,Math.min(1,b2*fraction + b1*(1-fraction))); color = new Color(r,g,b); break; case PALETTE_SPECTRUM: color = Color.getHSBColor(0.95F*fraction, 1, 1); break; case PALETTE_PALE_SPECTRUM: color = Color.getHSBColor(0.95F*fraction, 0.6F, 1); break; case PALETTE_GRAYSCALE: color = new Color(0.9F*fraction,0.9F*fraction,0.9F*fraction); break; default: color = new Color(1-0.9F*fraction,1-0.9F*fraction,1-0.9F*fraction); break; } palette[i] = color.getRGB(); } } /** * Called by worker threads to get the next available job. Computation of an * image is broken up into a set of jobs that are performed by worker threads. * This method is used to assign a new jobs to a thread each time it completes * a job. When no jobs are available (between computations or before any computation * is begun), this method will block, which will keep the threads idle. * @return */ synchronized private Job getNextJob() { while (!computing && !shutDown) { try { wait(); } catch (InterruptedException e) { } } if (shutDown) return null; else if (jobsAssigned >= jobs) return null; else { Job job = new Job(); job.rowNumber = jobsAssigned; job.xmin = xmin; job.dx = dx; job.y = ymax - jobsAssigned*dy; job.maxIterations = maxIterations; job.count = imageWidth; job.computationNumber = computationNumber; jobsAssigned++; return job; } } /** * This is called by a worker thread when it finished a job. The job is added to * the queue of finished jobs. If all jobs have been completed, the stopComputing() * method is called. */ synchronized private void finish(Job job) { if (job.computationNumber != computationNumber) return; finishedJobs.addLast(job); jobsCompleted++; if (jobsCompleted == jobs) stopComputing(); } /** * This class represents one job, which consists of doing the Mandelbrot computation * loop and counting the iterations for each pixel in one row of pixels. All the * data necessary for the computation is stored in the job object. The * computationNumber identifies which computation this job is part of. The output * of the jobs, consisting of an array of iteration counts, is stored in the * iterationCounts instance variable when the job finishes. */ private class Job { double xmin; double dx; double y; int count; int maxIterations; int rowNumber; int computationNumber; int[] iterationCounts; void compute() { iterationCounts = new int[count]; for (int i = 0; i < count; i++) { double x0 = xmin + i * dx; double y0 = y; double a = x0; double b = y0; int ct = 0; while (a*a + b*b < 4.1) { ct++; if (ct > maxIterations) { ct = -1; break; } double newa = a*a - b*b + x0; b = 2*a*b + y0; a = newa; } iterationCounts[i] = ct; } } } /** * Class that defines the worker threads. The thread is very simple. It just * loops forever, getting jobs to do and carrying out each job. */ private class ComputeThread extends Thread { public void run() { while (true) { Job job = getNextJob(); // blocks until a job is available. if (shutDown) break; if (job != null) { job.compute(); // does the work. finish(job); } } } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -