001/* 002 * Renderer 4. The MIT License. 003 * Copyright (c) 2022 rlkraft@pnw.edu 004 * See LICENSE for details. 005*/ 006 007package renderer.scene.util; 008 009import renderer.scene.*; 010import renderer.scene.primitives.*; 011 012import java.util.ArrayList; 013import java.awt.Color; 014 015/** 016 Convert a {@link Model} object into a point cloud {@link Model}. 017<p> 018 See <a href="https://en.wikipedia.org/wiki/Point_cloud" target="_top"> 019 https://en.wikipedia.org/wiki/Point_cloud</a> 020*/ 021public class PointCloud 022{ 023 /** 024 A static factory method that converts a given {@link Model} 025 into a {@link Model} made up of only {@link Point} primitives. 026 027 @param model {@link Model} to convert into a point cloud 028 @return a {@link Model} that is a point cloud version of the input {@link Model} 029 @throws NullPointerException if {@code model} is {@code null} 030 */ 031 public static Model make(final Model model) 032 { 033 return make(model, 0); // set the point size to 0 034 } 035 036 037 /** 038 A static factory method that converts a given {@link Model} 039 into a {@link Model} made up of only {@link Point} primitives. 040 041 @param model {@link Model} to convert into a point cloud 042 @param pointSize integer diameter of the rasterized points 043 @return a {@link Model} that is a point cloud version of the input {@link Model} 044 @throws NullPointerException if {@code model} is {@code null} 045 @throws IllegalArgumentException if {@code pointSize} is less than 0 046 */ 047 public static Model make(final Model model, final int pointSize) 048 { 049 if (null == model) 050 throw new NullPointerException("model must not be null"); 051 if (pointSize < 0) 052 throw new IllegalArgumentException("pointSize must be greater than or equal to 0"); 053 054 final Model pointCloud = new Model(new ArrayList<Vertex>(model.vertexList), 055 new ArrayList<>(), // empty primitiveList 056 new ArrayList<Color>(model.colorList), 057 "PointCloud: " + model.name, 058 model.visible); 059 060 // Find the vertices that are being used by a primitive. 061 final boolean[] vIndices = new boolean[model.vertexList.size()]; 062 final int[] cIndices = new int[model.vertexList.size()]; 063 064 for (final Primitive p : model.primitiveList) 065 { 066 for (int i = 0; i < p.vIndexList.size(); ++i) 067 { 068 vIndices[p.vIndexList.get(i)] = true; 069 cIndices[p.vIndexList.get(i)] = p.cIndexList.get(i); 070 } 071 } 072 073 // Create a Point for each vertex that is used by some primitive. 074 for (int i = 0; i < vIndices.length; ++i) 075 { 076 if ( vIndices[i] ) 077 { 078 pointCloud.addPrimitive( new Point(i, cIndices[i]) ); 079 } 080 } 081 082 // Set the radius for each new Point primitive. 083 for (final Primitive p : pointCloud.primitiveList) 084 { 085 ((Point)p).radius = pointSize;; 086 } 087 088 return pointCloud; 089 } 090 091 092 093 // Private default constructor to enforce noninstantiable class. 094 // See Item 4 in "Effective Java", 3rd Ed, Joshua Bloch. 095 private PointCloud() { 096 throw new AssertionError(); 097 } 098}