FieldLines.java


Below is the syntax highlighted version of FieldLines.java from §3.2 Creating Data Types.


/******************************************************************************
 *  Compilation:  javac FieldLines.java
 *  Execution:    java FieldLines n
 *  Dependencies: https://introcs.cs.princeton.edu/32class/DeluxeCharge.java
 *
 *  Written by Kevin Wayne and Zhijin Liu.
 *
 ******************************************************************************/

import java.awt.Color;

public class FieldLines {

    public static void main(String[] args) {
        int SIZE = 250;                     // size of window
        double RADIUS = 500E-12;            // real size (m)
        int FIELD_LINES = 16;               // number of fields per charge to draw
        double eps = RADIUS / SIZE;         // real size of 1 pixel
        double EPSILON = eps / 1.0E5;
        double e = 1.60217733E-19;          // elementary charge (C)

        // n random charges
        int n = Integer.parseInt(args[0]);
        DeluxeCharge[] charges = new DeluxeCharge[n];
        for (int i = 0; i < n; i++) {
            double x = Math.random() * RADIUS;
            double y = Math.random() * RADIUS;
            double k = e;
            if (Math.random() < 0.5) k = -e;
            charges[i] = new DeluxeCharge(x, y, k);
        }


        charges[0] = new DeluxeCharge(RADIUS/2, RADIUS/2 + RADIUS/8,  e);
        charges[1] = new DeluxeCharge(RADIUS/2, RADIUS/2 - RADIUS/8,  -e);


/*
      // Helium nucleus and two nearby electrons
        charges[0] = new DeluxeCharge(RADIUS/2, RADIUS/2,          e);
        charges[1] = new DeluxeCharge(RADIUS/2, RADIUS/2,          e);
        charges[2] = new DeluxeCharge(RADIUS/2, RADIUS/2,          0);
        charges[3] = new DeluxeCharge(RADIUS/2, RADIUS/2,          0);
        charges[4] = new DeluxeCharge(RADIUS/2+128e-12, RADIUS/2, -e);
        charges[5] = new DeluxeCharge(RADIUS/2, RADIUS/2+128e-12, -e);
*/


/*
      // 3 dipoles
        charges[0] = new DeluxeCharge(RADIUS/4 - 8e-12, RADIUS/4,        e);
        charges[1] = new DeluxeCharge(RADIUS/4 + 8e-12, RADIUS/4,       -e);
        charges[2] = new DeluxeCharge(RADIUS/4 - 8e-12, RADIUS*3/4,      e);
        charges[3] = new DeluxeCharge(RADIUS/4 + 8e-12, RADIUS*3/4,     -e);
        charges[4] = new DeluxeCharge(RADIUS*3/4,       RADIUS/2+8e-12,  e);
        charges[5] = new DeluxeCharge(RADIUS*3/4,       RADIUS/2-8e-12, -e);
*/

        StdDraw.setCanvasSize(SIZE, SIZE);
        StdDraw.setXscale(0, SIZE);
        StdDraw.setYscale(0, SIZE);

        // compute potential at each gridpoint (x, y)
        for (int ix = 0; ix < SIZE; ix++) {
            for (int iy = 0; iy < SIZE; iy++) {
                double x = ix * RADIUS / SIZE;
                double y = iy * RADIUS / SIZE;
                double V = 0.0;
                for (int i = 0; i < n; i++) {
                    V += charges[i].potentialAt(x, y);
                }

                // draw potential according in color from red to blue
                int h = 120 - (int) (V * 3);
                if (h < 0)   h = 0;
                if (h > 240) h = 240;
                Color color = Color.getHSBColor(h / 360.0f, 1.0f, 1.0f);
                StdDraw.setPenColor(color);
                StdDraw.point(ix, iy);
            }
        }

        StdDraw.show();

        // draw field lines
        StdDraw.setPenColor(StdDraw.WHITE);
        for (int j = 0; j < n; j++) {
            for (int k = 0; k < FIELD_LINES; k++) {

                // start the lines on a circle around the charge
                // perhaps add randomAngle = Math.random(); to each angle to avoid
                // degenerate case and infinite loop with 2 equal and aligned charges
                double x = charges[j].getX() + eps * Math.cos(2 * Math.PI * k / FIELD_LINES);
                double y = charges[j].getY() + eps * Math.sin(2 * Math.PI * k / FIELD_LINES);
                boolean reachedAnotherCharge = false;
                // Check for infinite loop
                boolean infiniteLoop = false;
                int count = 0;
                double[] oldXs = { 0.0, 0.0 };
                double[] oldYs = { 0.0, 0.0 };

                while (!reachedAnotherCharge && !infiniteLoop
                        && x > 0 && x < RADIUS && y > 0 && y < RADIUS) {

                    // find the field (Ex, Ey) and field strength E at (x,y)
                    double Ex = 0.0, Ey = 0.0;
                    for (int i = 0; i < n; i++) {
                        Ex += charges[i].fieldX(x, y);
                        Ey += charges[i].fieldY(x, y);
                    }
                    double E = Math.sqrt(Ex * Ex + Ey * Ey);

                    // if charge is negative the line needs to go backwards
                    if (charges[j].isPositivelyCharged()) {
                        x += Ex / E * eps;
                        y += Ey / E * eps;
                    }
                    else {
                        x -= Ex / E * eps;
                        y -= Ey / E * eps;
                    }
                    StdDraw.point(x / eps, y / eps);

                    // stop in infinite loop
                    if (Math.abs(x - oldXs[0]) < EPSILON && Math.abs(y - oldYs[0]) < EPSILON) {
                        infiniteLoop = true;
                    }
                    int index = count++ % 2;
                    oldXs[index] = x;
                    oldYs[index] = y;

                    // stop if the line ends in a charge
                    for (int i = 0; i < n; i++)
                        if (charges[i].distanceTo(x, y) < eps) reachedAnotherCharge = true;
                }
            }
        }
        StdDraw.show();
        // StdDraw.save("dipole.png");
    }
}


Copyright © 2000–2022, Robert Sedgewick and Kevin Wayne.
Last updated: Thu Aug 11 10:22:50 EDT 2022.