private void populateSmartShape(boolean closed) {

		if (smartShape == null)
			return;

		if (model.getNumberOfParticles() >= atom.length) {
			errorReminder.show(ErrorReminder.EXCEED_CAPACITY);
			smartShape = null;
			return;
		}

		Polygon tempPoly = new Polygon();
		double vdw = model.getElement(MolecularObject.getElement()).getSigma();
		double vdwsq = vdw * vdw;

		switch (actionID) {

		case SFRE_ID:

			double dx,
			dy,
			sq1,
			sq2;
			PathIterator pi = smartShape.getPathIterator(null);
			double[] xy = new double[6];
			int nd = 0,
			nPrevSegm = 0;
			double x1 = 0.0,
			y1 = 0.0;
			while (!pi.isDone()) {
				int type = pi.currentSegment(xy);
				if (type == PathIterator.SEG_MOVETO || type == PathIterator.SEG_LINETO) {
					if (tempPoly.npoints == 0) {
						tempPoly.addPoint((int) xy[0], (int) xy[1]);
					} else {
						nPrevSegm = tempPoly.npoints - 1; // densify the sampling points
						dx = xy[0] - tempPoly.xpoints[nPrevSegm];
						dy = xy[1] - tempPoly.ypoints[nPrevSegm];
						sq1 = dx * dx + dy * dy;
						nd = (int) (Math.sqrt(sq1) / vdw) - 1;
						for (int i = 1; i < nd; i++) {
							x1 = tempPoly.xpoints[nPrevSegm] + dx * i / nd;
							y1 = tempPoly.ypoints[nPrevSegm] + dy * i / nd;
							tempPoly.addPoint((int) x1, (int) y1);
						}
						dx = xy[0] - tempPoly.xpoints[0];
						dy = xy[1] - tempPoly.ypoints[0];
						if (dx * dx + dy * dy > vdwsq)
							tempPoly.addPoint((int) xy[0], (int) xy[1]);
					}
				}
				pi.next();
			}
			break;

		case SCUR_ID:
		case RCUR_ID:

			pi = smartShape.getPathIterator(null);
			xy = new double[6];
			Polygon poly = new Polygon();
			int type;
			while (!pi.isDone()) {
				type = pi.currentSegment(xy);
				if (type == PathIterator.SEG_MOVETO || type == PathIterator.SEG_LINETO)
					poly.addPoint((int) xy[0], (int) xy[1]);
				pi.next();
			}
			CurvedSurface.shrinkPolygon(poly, 0.6 * vdw);
			tempPoly.addPoint(poly.xpoints[0], poly.ypoints[0]);
			for (int i = 1; i < poly.npoints; i++) {
				dx = tempPoly.xpoints[tempPoly.npoints - 1] - poly.xpoints[i];
				dy = tempPoly.ypoints[tempPoly.npoints - 1] - poly.ypoints[i];
				sq1 = dx * dx + dy * dy;
				if (tempPoly.npoints > 1) {
					dx = tempPoly.xpoints[0] - poly.xpoints[i];
					dy = tempPoly.ypoints[0] - poly.ypoints[i];
					sq2 = dx * dx + dy * dy;
					if (sq1 >= vdwsq && sq2 >= vdwsq)
						tempPoly.addPoint(poly.xpoints[i], poly.ypoints[i]);
				} else {
					if (sq1 >= vdwsq)
						tempPoly.addPoint(poly.xpoints[i], poly.ypoints[i]);
				}
			}
			break;

		case SCIR_ID:
		case RCIR_ID:

			if (smartShape instanceof Ellipse) {
				Ellipse2D el = (Ellipse2D) smartShape;
				double sigma = 0.6 * vdw;
				double w2 = el.getWidth() * 0.5 - sigma;
				double h2 = el.getHeight() * 0.5 - sigma;
				double x0 = el.getX() + w2 + sigma;
				double y0 = el.getY() + h2 + sigma;
				int n = (int) (5 * Math.PI * (w2 + h2) / vdw);
				double px = x0 + w2, py = y0;
				dx = dy = 0.0;
				double theta = 0.0;
				tempPoly.addPoint((int) px, (int) py);
				for (int i = 1; i < n - 1; i++) {
					theta = 2.0 * i / n * Math.PI;
					px = x0 + w2 * Math.cos(theta);
					py = y0 + h2 * Math.sin(theta);
					dx = px - tempPoly.xpoints[tempPoly.npoints - 1];
					dy = py - tempPoly.ypoints[tempPoly.npoints - 1];
					if (dx * dx + dy * dy >= vdwsq) {
						dx = px - tempPoly.xpoints[0];
						dy = py - tempPoly.ypoints[0];
						if (dx * dx + dy * dy >= vdwsq)
							tempPoly.addPoint((int) px, (int) py);
					}
				}
			}
			break;

		case SREC_ID:
		case RREC_ID:

			if (smartShape instanceof RoundRectangle) {
				RoundRectangle rt = (RoundRectangle) smartShape;
				double sigma = 0.6 * vdw;
				double w = rt.getWidth() - 2 * sigma;
				double h = rt.getHeight() - 2 * sigma;
				double x = rt.getX() + sigma;
				double y = rt.getY() + sigma;
				tempPoly.addPoint((int) x, (int) y);
				int n = (int) (w / vdw * 0.95);
				for (int i = 1; i < n; i++)
					tempPoly.addPoint((int) (x + w * i / n), (int) y);
				int c1 = tempPoly.npoints;
				tempPoly.addPoint((int) (x + w), (int) y);
				n = (int) (h / vdw * 0.95);
				for (int i = 1; i < n; i++)
					tempPoly.addPoint((int) (x + w), (int) (y + h * i / n));
				int c2 = tempPoly.npoints;
				tempPoly.addPoint((int) (x + w), (int) (y + h));
				for (int i = c1 - 1; i > 0; i--)
					tempPoly.addPoint(tempPoly.xpoints[i], (int) (y + h));
				tempPoly.addPoint((int) x, (int) (y + h));
				for (int i = c2 - 1; i > c1; i--)
					tempPoly.addPoint((int) x, tempPoly.ypoints[i]);
			}
			break;

		}

		int min = 3;
		switch (actionID) {
		case RCUR_ID:
			min = 2;
			/*
			 * if the path is a straight line, PathIterator will not find the intermediate points, therefore, we need to divide the line manually.
			 */
			if (tempPoly.npoints == 2) {
				int x0 = tempPoly.xpoints[0];
				int y0 = tempPoly.ypoints[0];
				int x1 = tempPoly.xpoints[1];
				int y1 = tempPoly.ypoints[1];
				float xx = x1 - x0;
				float yy = y1 - y0;
				int n = (int) Math.sqrt((xx * xx + yy * yy) / vdwsq * 0.95);
				xx /= n;
				yy /= n;
				tempPoly.reset();
				for (int i = 0; i < n; i++)
					tempPoly.addPoint((int) (x0 + i * xx), (int) (y0 + i * yy));
				tempPoly.addPoint(x1, y1);
			}
			break;
		case SCUR_ID:
			min = 3;
			break;
		}
		if (tempPoly.npoints >= min) {
			if (!isSelfCrossed(tempPoly) && isShapeFine(tempPoly, (int) (0.8 * vdw))) {
				if (!intersects(tempPoly)) {
					if (boundary.contains(tempPoly.getBounds2D())) {
						switch (actionID) {
						case SFRE_ID:
							molecules.add(closed ? new CurvedSurface(tempPoly, model) : new CurvedRibbon(tempPoly, model, false));
							break;
						case RCUR_ID:
							molecules.add(new CurvedRibbon(tempPoly, model, closed));
							break;
						case RCIR_ID:
						case RREC_ID:
							molecules.add(new CurvedRibbon(tempPoly, model, true));
							break;
						case SCUR_ID:
						case SCIR_ID:
						case SREC_ID:
							molecules.add(new CurvedSurface(tempPoly, model));
							break;
						}
						model.notifyChange();
						if (!doNotFireUndoEvent) {
							molecules.get(molecules.size() - 1).setSelected(true);
							model.getUndoManager().undoableEditHappened(new UndoableEditEvent(model, new UndoableInsertion(actionID, new Object[] { new Boolean(closed), tempPoly })));
							updateUndoUIComponents();
						}
					} else {
						errorReminder.show(ErrorReminder.OUT_OF_BOUND);
					}
				} else {
					errorReminder.show(ErrorReminder.OBJECT_OVERLAP);
				}
			} else {
				errorReminder.show(ErrorReminder.SELF_CROSS);
			}
			smartShape = null;
		}
	}