Loading src/main/java/com/elphel/imagej/tileprocessor/lwoc/LwocMesh.java +4 −4 Original line number Original line Diff line number Diff line Loading @@ -25,11 +25,11 @@ package com.elphel.imagej.tileprocessor.lwoc; package com.elphel.imagej.tileprocessor.lwoc; import java.io.Serializable; import java.io.Serializable; import java.util.concurrent.atomic.AtomicInteger; ///import java.util.concurrent.atomic.AtomicInteger; public class LwocMesh implements Serializable { public class LwocMesh implements Serializable { private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L; static AtomicInteger MESH_ID = new AtomicInteger(); /// static AtomicInteger MESH_ID = new AtomicInteger(); // static ArrayList<LwocMesh> LWOC_MESHES; // static ArrayList<LwocMesh> LWOC_MESHES; int id; // assign unique ID int id; // assign unique ID String stimestamp; // mesh is always referenced to a single scene String stimestamp; // mesh is always referenced to a single scene Loading @@ -37,7 +37,7 @@ public class LwocMesh implements Serializable { double [] hdims_xyz; // world bounding box half-dimensions along x,y,z double [] hdims_xyz; // world bounding box half-dimensions along x,y,z public static void resetMeshes() { public static void resetMeshes() { MESH_ID.set(0); /// MESH_ID.set(0); // LWOC_MESHES = new ArrayList<LwocMesh>(); // LWOC_MESHES = new ArrayList<LwocMesh>(); } } // maybe use mesh properties instead of id? // maybe use mesh properties instead of id? Loading @@ -48,7 +48,7 @@ public class LwocMesh implements Serializable { String stimestamp String stimestamp ) { ) { this.stimestamp = stimestamp; this.stimestamp = stimestamp; id = MESH_ID.getAndIncrement(); /// id = MESH_ID.getAndIncrement(); // LWOC_MESHES.add(this); // LWOC_MESHES.add(this); } } Loading src/main/java/com/elphel/imagej/tileprocessor/lwoc/LwocOctree.java +83 −147 Original line number Original line Diff line number Diff line Loading @@ -24,11 +24,11 @@ package com.elphel.imagej.tileprocessor.lwoc; package com.elphel.imagej.tileprocessor.lwoc; import java.io.FileInputStream; //import java.io.FileInputStream; import java.io.FileOutputStream; //import java.io.FileOutputStream; import java.io.IOException; //import java.io.IOException; import java.io.ObjectInputStream; //import java.io.ObjectInputStream; import java.io.ObjectOutputStream; //import java.io.ObjectOutputStream; import java.io.Serializable; import java.io.Serializable; import java.util.ArrayList; import java.util.ArrayList; import java.util.List; import java.util.List; Loading @@ -37,99 +37,21 @@ import com.elphel.imagej.common.MultiThreading; public class LwocOctree implements Serializable { public class LwocOctree implements Serializable { private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L; public static final int NUM_CHILDREN = 8; public static final int NUM_CHILDREN = 8; public static double MIN_HSIZE = 0.3; // meter - do not subdivide more // static AtomicInteger OCTREE_ID = new AtomicInteger(); // can not be used as intersecting meshes' bb will not decrease number after splitting public static int MAX_MESH_CENTERS = 10; // maximal number of meshes in a leaf; public static int MAX_CAMERAS = 10; // maximal number of cameras in a leaf; public static LwocOctree lwoc_root = null; // static ArrayList<LwocOctree> LWOK_OCTREE = new ArrayList<LwocOctree>(); static AtomicInteger OCTREE_ID = new AtomicInteger(); static List<LwocScene> pendingScenes; // synchronized - add not-yet-added scenes pending growing world static List<LwocScene> pendingScenes; // synchronized - add not-yet-added scenes pending growing world static List<LwocMesh> pendingMeshes; // synchronized - add not-yet-added meshes pending growing world static List<LwocMesh> pendingMeshes; // synchronized - add not-yet-added meshes pending growing world static List<LwocOctree> pendingLeafNodes;// synchronized - leaf nodes needed to be split static List<LwocOctree> pendingLeafNodes;// synchronized - leaf nodes needed to be split // static List<LwocWorld> lwoc_worlds; // int id; // assign unique ID int id; // assign unique ID LwocOctree parent; transient LwocWorld world; transient LwocOctree parent; LwocOctree [] children; LwocOctree [] children; LwocLeaf leaf; // LwocLeaf leaf; // double [] center; // x-center, y-center, z-center double [] center; // x-center, y-center, z-center double hsize; double hsize; /** * Serialize and write world to an output stream * @param oos ObjectOutputStream to write to. * @throws IOException */ private void writeObject(ObjectOutputStream oos) throws IOException { oos.defaultWriteObject(); if (parent == null) { // write static members oos.writeObject(MIN_HSIZE); oos.writeObject(MAX_MESH_CENTERS); oos.writeObject(MAX_CAMERAS); oos.writeObject(OCTREE_ID.get()); oos.writeObject(LwocMesh.MESH_ID.get()); } } /** * Read input stream and deserialize it to world octree structure. * @param ois ObjectInputStream to read from * @throws ClassNotFoundException * @throws IOException */ private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { ois.defaultReadObject(); if (parent == null) { // read static members MIN_HSIZE = (Double) ois.readObject(); MAX_MESH_CENTERS = (Integer) ois.readObject(); MAX_CAMERAS = (Integer) ois.readObject(); OCTREE_ID.set( (Integer) ois.readObject()); LwocMesh.MESH_ID.set((Integer) ois.readObject()); } } /** * * @param path */ public static void saveWorld(String path) { try { FileOutputStream fileOut = new FileOutputStream(path); ObjectOutputStream out = new ObjectOutputStream(fileOut); out.writeObject(lwoc_root); // will cause all world to be saved out.close(); fileOut.close(); System.out.printf("Serialized data is saved in "+path); } catch (IOException e) { e.printStackTrace(); } } public static void restoreWorld(String path) { try { FileInputStream fileIn = new FileInputStream(path); ObjectInputStream in = new ObjectInputStream(fileIn); lwoc_root = (LwocOctree) in.readObject(); in.close(); fileIn.close(); } catch (IOException e) { e.printStackTrace(); return; } catch (ClassNotFoundException c) { System.out.println(path+" not found"); c.printStackTrace(); return; } } public static void addPendingScene(LwocScene scene) { public static void addPendingScene(LwocScene scene) { synchronized(pendingScenes) { synchronized(pendingScenes) { pendingScenes.add(scene); pendingScenes.add(scene); Loading @@ -148,22 +70,6 @@ public class LwocOctree implements Serializable { } } } } /** * Initialize Octree data and set initial world node. It is possible to grow * world as needed later. * @param center world center: x,y,z in meters. Usually {0,0,0} * @param world_hsize Half linear dimension of the world */ public static void initOctree(double [] center, double world_hsize) { LwocMesh.resetMeshes(); LwocScene.resetScenes(); resetPending(); // LWOK_OCTREE = new ArrayList<LwocOctree>(); // Add a single leaf node lwoc_root = new LwocOctree(null, center, world_hsize); lwoc_root.leaf = new LwocLeaf(); } /** /** * Synchronized lists of pending scenes, meshes and nodes are used to delay modification of * Synchronized lists of pending scenes, meshes and nodes are used to delay modification of * the world octree and its elements from the multithreaded environment. These lists should * the world octree and its elements from the multithreaded environment. These lists should Loading Loading @@ -202,18 +108,19 @@ public class LwocOctree implements Serializable { /** /** * LwocOctree constructor * LwocOctree constructor * @param lwocWorld World global parameters * @param parent Parent node * @param parent Parent node * @param xyz position of the node center in meters * @param xyz Position of the node center in meters * @param hsize Node half size - each of the X,Y,Z coordinates of the internal * @param hsize Node half size - each of the X,Y,Z coordinates of the internal * points are limited within +/-hsize from the node center * points are limited within +/-hsize from the node center */ */ public LwocOctree (LwocOctree parent, public LwocOctree ( LwocWorld lwocWorld, LwocOctree parent, double [] xyz, double [] xyz, double hsize) { double hsize) { id = OCTREE_ID.getAndIncrement(); this.parent = parent; this.parent = parent; this.hsize = hsize; this.hsize = hsize; // LWOK_OCTREE.add(this); } } /** /** Loading @@ -222,14 +129,15 @@ public class LwocOctree implements Serializable { * @return Octree node that includes the point or null if the point * @return Octree node that includes the point or null if the point * is outside the root node (the whole world) * is outside the root node (the whole world) */ */ public static LwocOctree getLeafNode( // if null - needs growing world //FIXME: obey border (on the edges of max hsize of the root) nodes public LwocOctree getLeafNode( // if null - needs growing world double [] xyz) { // thread safe double [] xyz) { // thread safe if (!lwoc_root.contains(xyz)) return null; // needs growing world if (!world.getLwocRoot().contains(xyz)) return null; // needs growing world LwocOctree node = lwoc_root; LwocOctree node = world.getLwocRoot(); while (lwoc_root.children != null) { while (world.getLwocRoot().children != null) { int indx = 0; int indx = 0; for (int dm = 0; dm < 3; dm++) { for (int dm = 0; dm < 3; dm++) { if (xyz[dm] >= lwoc_root.center[dm] ) { if (xyz[dm] >= world.getLwocRoot().center[dm] ) { indx += 1 << dm; indx += 1 << dm; } } } } Loading @@ -245,7 +153,7 @@ public class LwocOctree implements Serializable { * @param check_existed - do not add duplicate scenes and nodes * @param check_existed - do not add duplicate scenes and nodes * @return An octree node where scene is added or null if the world needs growing * @return An octree node where scene is added or null if the world needs growing */ */ public static LwocOctree addScene( public LwocOctree addScene( LwocScene scene, LwocScene scene, boolean check_existed boolean check_existed ) {// returns null and adds to pendingScenes if needs growing ) {// returns null and adds to pendingScenes if needs growing Loading @@ -259,8 +167,8 @@ public class LwocOctree implements Serializable { } else { } else { node.leaf.addScene(scene,check_existed); node.leaf.addScene(scene,check_existed); // Check if leaf node requires splitting // Check if leaf node requires splitting if (node.leaf.getScenes().size() > MAX_CAMERAS) { if (node.leaf.getScenes().size() > world.getMaxCameras()) { if (node.hsize > MIN_HSIZE) { if (node.hsize > world.getMinHsize()) { if (!check_existed || !pendingLeafNodes.contains(node)) { if (!check_existed || !pendingLeafNodes.contains(node)) { addPendingLeafNode(node); addPendingLeafNode(node); } } Loading @@ -274,7 +182,7 @@ public class LwocOctree implements Serializable { * Tend to pending scenes list. Not thread-safe, should be run in a single-thread mode. * Tend to pending scenes list. Not thread-safe, should be run in a single-thread mode. * @param check_existed - do not add duplicate scenes and nodes * @param check_existed - do not add duplicate scenes and nodes */ */ public static void tendPendingScenes( public void tendPendingScenes( boolean check_existed boolean check_existed ) { ) { if (pendingScenes.isEmpty()) { if (pendingScenes.isEmpty()) { Loading @@ -295,7 +203,7 @@ public class LwocOctree implements Serializable { * Only adds mesh centers and grows the world if needed. * Only adds mesh centers and grows the world if needed. * @param check_existed do not add duplicate meshes * @param check_existed do not add duplicate meshes */ */ public static void tendPendingMeshCentersOnly( public void tendPendingMeshCentersOnly( boolean check_existed boolean check_existed ) { ) { if (pendingMeshes.isEmpty()) { if (pendingMeshes.isEmpty()) { Loading Loading @@ -326,14 +234,14 @@ public class LwocOctree implements Serializable { * Should be run after tendPendingMeshCentersOnly(). * Should be run after tendPendingMeshCentersOnly(). * @param check_existed do not add duplicate meshes * @param check_existed do not add duplicate meshes */ */ public static void tendPendingMeshes( public void tendPendingMeshes( boolean check_existed ) { boolean check_existed ) { if (pendingMeshes.isEmpty()) { if (pendingMeshes.isEmpty()) { return; // nothing to do return; // nothing to do } else { } else { for (LwocMesh mesh: pendingMeshes) { for (LwocMesh mesh: pendingMeshes) { // int num_added = // int num_added = lwoc_root.addMesh( world.lwoc_root.addMesh( mesh, mesh, check_existed); check_existed); } } Loading Loading @@ -417,6 +325,7 @@ public class LwocOctree implements Serializable { xyz[dm] +=new_hsize * ((((nchild >> dm) & 1) > 0)? 1 : -1); xyz[dm] +=new_hsize * ((((nchild >> dm) & 1) > 0)? 1 : -1); } } children[nchild] = new LwocOctree( children[nchild] = new LwocOctree( world, this, this, xyz, xyz, new_hsize); new_hsize); Loading Loading @@ -481,41 +390,44 @@ public class LwocOctree implements Serializable { * until the specified point gets inside. Not thread safe, should run in single-thread mode * until the specified point gets inside. Not thread safe, should run in single-thread mode * @param xyz The point to be included in the world. * @param xyz The point to be included in the world. */ */ public static void growXYZ(double [] xyz) { public void growXYZ(double [] xyz) { while (!lwoc_root.contains(xyz)) {// already fits, do not grow while (!world.lwoc_root.contains(xyz)) {// already fits, do not grow // grow once // grow once int indx=0; //direction to grow int indx=0; //direction to grow double [] new_center = new double[3]; double [] new_center = new double[3]; double [] root_center = world.lwoc_root.center; double root_hsize = world.lwoc_root.hsize; for (int dm = 0; dm < new_center.length; dm++) { for (int dm = 0; dm < new_center.length; dm++) { if (xyz[dm] >= lwoc_root.center[dm] ) { if (xyz[dm] >= root_center[dm] ) { indx += 1 << dm; indx += 1 << dm; new_center[dm]= lwoc_root.center[dm] + lwoc_root.hsize; new_center[dm]= root_center[dm] + root_hsize; } else { } else { new_center[dm]= lwoc_root.center[dm] - lwoc_root.hsize; new_center[dm]= root_center[dm] - root_hsize; } } } } LwocOctree new_root = new LwocOctree(null, new_center, lwoc_root.hsize * 2); LwocOctree new_root = new LwocOctree(world,null, new_center, world.lwoc_root.hsize * 2); new_root.children = new LwocOctree[NUM_CHILDREN]; new_root.children = new LwocOctree[NUM_CHILDREN]; int child = (~indx ) & (NUM_CHILDREN -1); // opposite direction, from new root to old root int child = (~indx ) & (NUM_CHILDREN -1); // opposite direction, from new root to old root for (int ichild = 0; ichild < NUM_CHILDREN; ichild++) { for (int ichild = 0; ichild < NUM_CHILDREN; ichild++) { if (ichild == child) { if (ichild == child) { lwoc_root.parent = new_root; world.lwoc_root.parent = new_root; new_root.children[ichild] = lwoc_root; new_root.children[ichild] = world.lwoc_root; } else { // create empty leaf nodes } else { // create empty leaf nodes new_root.children[ichild] = new LwocOctree( new_root.children[ichild] = new LwocOctree( world, new_root, new_root, new double [] { new double [] { new_center[0] + lwoc_root.hsize * ((((child >> 0) & 1) > 0)? 1 : -1), new_center[0] + root_hsize * ((((child >> 0) & 1) > 0)? 1 : -1), new_center[1] + lwoc_root.hsize * ((((child >> 1) & 1) > 0)? 1 : -1), new_center[1] + root_hsize * ((((child >> 1) & 1) > 0)? 1 : -1), new_center[2] + lwoc_root.hsize * ((((child >> 2) & 1) > 0)? 1 : -1) new_center[2] + root_hsize * ((((child >> 2) & 1) > 0)? 1 : -1) }, }, lwoc_root.hsize); root_hsize); // add leaf // add leaf new_root.children[ichild].leaf = new LwocLeaf(); new_root.children[ichild].leaf = new LwocLeaf(); } } } } lwoc_root = new_root; world.lwoc_root = new_root; } } } } Loading @@ -525,6 +437,7 @@ public class LwocOctree implements Serializable { * @param half_whd half width(x), height(y) and depth(z) * @param half_whd half width(x), height(y) and depth(z) * @return True if it intersects * @return True if it intersects */ */ //FIXME: obey border (on the edges of max hsize of the root) nodes public boolean intersects ( public boolean intersects ( double [] xyz, double [] xyz, double [] half_whd) { double [] half_whd) { Loading @@ -544,6 +457,7 @@ public class LwocOctree implements Serializable { * @param xyz point * @param xyz point * @return True if it intersects * @return True if it intersects */ */ //FIXME: obey border (on the edges of max hsize of the root) nodes public boolean contains ( public boolean contains ( double [] xyz) { double [] xyz) { for (int dm = 0; dm < center.length; dm++) { for (int dm = 0; dm < center.length; dm++) { Loading @@ -563,6 +477,8 @@ public class LwocOctree implements Serializable { * @param half_whd half width(x), height(y) and depth(z) * @param half_whd half width(x), height(y) and depth(z) * @return True if it intersects * @return True if it intersects */ */ //FIXME: obey border (on the edges of max hsize of the root) nodes public boolean contains ( public boolean contains ( double [] xyz, double [] xyz, double [] half_whd) { double [] half_whd) { Loading @@ -584,7 +500,7 @@ public class LwocOctree implements Serializable { * @param check_existed Add only if the same mesh did not exist * @param check_existed Add only if the same mesh did not exist * @return number of nodes it was added to (intersecting) * @return number of nodes it was added to (intersecting) */ */ public static boolean addMeshCenter( // returns 0 and adds to pendingMeshes if needs growing public boolean addMeshCenter( // returns 0 and adds to pendingMeshes if needs growing LwocMesh mesh, LwocMesh mesh, boolean check_existed boolean check_existed ) { ) { Loading @@ -594,7 +510,7 @@ public class LwocOctree implements Serializable { double [] corner_xyz = center.clone(); double [] corner_xyz = center.clone(); for (int dm = 0; dm < center.length; dm++) { for (int dm = 0; dm < center.length; dm++) { corner_xyz[dm] += dims[dm]; corner_xyz[dm] += dims[dm]; if (!lwoc_root.contains(corner_xyz)){ if (!world.lwoc_root.contains(corner_xyz)){ if (pendingMeshes != null) { if (pendingMeshes != null) { if (!check_existed || !pendingMeshes.contains(mesh)) { if (!check_existed || !pendingMeshes.contains(mesh)) { addPendingMesh(mesh); addPendingMesh(mesh); Loading @@ -603,7 +519,7 @@ public class LwocOctree implements Serializable { return false; return false; } } corner_xyz[dm] -= 2*dims[dm]; corner_xyz[dm] -= 2*dims[dm]; if (!lwoc_root.contains(corner_xyz)){ if (!world.lwoc_root.contains(corner_xyz)){ if (pendingMeshes != null) { if (pendingMeshes != null) { if (!check_existed || !pendingMeshes.contains(mesh)) { if (!check_existed || !pendingMeshes.contains(mesh)) { addPendingMesh(mesh); addPendingMesh(mesh); Loading @@ -617,8 +533,8 @@ public class LwocOctree implements Serializable { LwocOctree node = getLeafNode(center); LwocOctree node = getLeafNode(center); node.leaf.addMeshCenter(mesh, check_existed); node.leaf.addMeshCenter(mesh, check_existed); // Check if leaf node requires splitting // Check if leaf node requires splitting if (node.leaf.getMeshCenters().size() > MAX_MESH_CENTERS) { if (node.leaf.getMeshCenters().size() > world.getMaxMeshCenters()) { if (node.hsize > MIN_HSIZE) { if (node.hsize > world.getMinHsize()) { if (!check_existed || !pendingLeafNodes.contains(node)) { if (!check_existed || !pendingLeafNodes.contains(node)) { addPendingLeafNode(node); addPendingLeafNode(node); } } Loading Loading @@ -659,7 +575,7 @@ public class LwocOctree implements Serializable { * Should fit in a root node (as it was earlier added) * Should fit in a root node (as it was earlier added) * @param mesh new mesh to add * @param mesh new mesh to add */ */ public static void removeMeshCenter( public void removeMeshCenter( LwocMesh mesh) { // check and remove duplicates LwocMesh mesh) { // check and remove duplicates LwocOctree node = getLeafNode(mesh.getCenter()); LwocOctree node = getLeafNode(mesh.getCenter()); node.leaf.removeMeshCenter(mesh); node.leaf.removeMeshCenter(mesh); Loading Loading @@ -688,6 +604,26 @@ public class LwocOctree implements Serializable { return removed; return removed; } } /** * Restore pointers to .parent and .world * @param world * @param parent */ public void restoreWorldParent( LwocWorld world, LwocOctree parent) { this.parent = parent; this.world = world; if (!isLeaf()) { for (LwocOctree child:children) { child.restoreWorldParent( world, // LwocWorld world, this); // LwocOctree parent) } } } /** /** * Recursively create a list of all leave nodes in the world. * Recursively create a list of all leave nodes in the world. * @return A list of all leaf nodes * @return A list of all leaf nodes Loading @@ -708,9 +644,9 @@ public class LwocOctree implements Serializable { * Rebuild meshes lists from mesh_centers for all leaf nodes after restoring the world. * Rebuild meshes lists from mesh_centers for all leaf nodes after restoring the world. * Used after restoring world from serialized form * Used after restoring world from serialized form */ */ public static void rebuildMeshLists( public void rebuildMeshLists( final boolean check_existed) { final boolean check_existed) { final List<LwocOctree> leaves = lwoc_root.getAllLeafNodes(); final List<LwocOctree> leaves = world.lwoc_root.getAllLeafNodes(); final List<LwocMesh> meshes = new ArrayList<LwocMesh>(); final List<LwocMesh> meshes = new ArrayList<LwocMesh>(); for (LwocOctree node : leaves) { for (LwocOctree node : leaves) { node.leaf.initMeshes(); node.leaf.initMeshes(); Loading @@ -726,7 +662,7 @@ public class LwocOctree implements Serializable { public void run() { public void run() { for (int indx_mesh = ai.getAndIncrement(); indx_mesh < meshes.size(); indx_mesh = ai.getAndIncrement()) { for (int indx_mesh = ai.getAndIncrement(); indx_mesh < meshes.size(); indx_mesh = ai.getAndIncrement()) { LwocMesh mesh = meshes.get(indx_mesh); LwocMesh mesh = meshes.get(indx_mesh); lwoc_root.addMesh(mesh, check_existed); world.lwoc_root.addMesh(mesh, check_existed); } } } } }; }; Loading src/main/java/com/elphel/imagej/tileprocessor/lwoc/LwocWorld.java 0 → 100644 +187 −0 Original line number Original line Diff line number Diff line /** ** ** LwocWorld.java - Octree world parameters (previous static) ** ** Copyright (C) 2022 Elphel, Inc. ** ** -----------------------------------------------------------------------------** ** ** LwocWorld.java is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see <http://www.gnu.org/licenses/>. ** -----------------------------------------------------------------------------** ** */ package com.elphel.imagej.tileprocessor.lwoc; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.List; public class LwocWorld implements Serializable { private static final long serialVersionUID = 1L; static List<LwocWorld> lwoc_worlds; // public double min_hsize; // = 0.3; // meter - do not subdivide more public double max_hsize; // = 10000.0; // meter - do not grow more public int max_mesh_centers; // = 10; // maximal number of meshes in a leaf; public int max_cameras; // = 10; // maximal number of cameras in a leaf; // public transient LwocOctree lwoc_root; // = null; public LwocOctree lwoc_root; // = null; public double [] atr; // = null; // Azimuth, tilt, roll - may be used to merge public double [] xyz; // = null; // this world offset (before rotation) or // null if not known. public LwocWorld ( double min_hsize, double max_hsize, int max_mesh_centers, int max_cameras, LwocOctree lwoc_root, double [] atr, double [] xyz) { setMinHsize (min_hsize); setMaxHsize (max_hsize); setMaxMeshCenters(max_mesh_centers); setMaxCameras (max_cameras); setLwocRoot (lwoc_root); setATR (atr); setXYZ (xyz); } public double getMinHsize() {return min_hsize;} public double getMaxHsize() {return max_hsize;} public int getMaxMeshCenters() {return max_mesh_centers;} public int getMaxCameras() {return max_cameras;} public LwocOctree getLwocRoot() {return lwoc_root;} public double [] getATR() {return atr;} public double [] getXYZ() {return xyz;} public void setMinHsize (double min_hsize) {this.min_hsize = min_hsize;} public void setMaxHsize (double max_hsize) {this.max_hsize = max_hsize;} public void setMaxMeshCenters(int max_mesh_centers) {this.max_mesh_centers = max_mesh_centers;} public void setMaxCameras (int max_cameras) {this.max_cameras = max_cameras;} public void setLwocRoot (LwocOctree lwoc_root) {this.lwoc_root = lwoc_root;} public void setATR (double [] atr) {this.atr = atr;} public void setXYZ (double [] xyz) {this.xyz = xyz;} /** * Serialize and write world to an output stream * @param oos ObjectOutputStream to write to. * @throws IOException */ private void writeObject(ObjectOutputStream oos) throws IOException { oos.defaultWriteObject(); // as of now - nothing else, custom for reads only // if (parent == null) { // write world members /* oos.writeObject(world.getMinHsize()); oos.writeObject(world.getMaxHsize()); oos.writeObject(world.getMaxMeshCenters()); oos.writeObject(world.getMaxCameras()); oos.writeObject(world.getATR()); oos.writeObject(world.getXYZ()); */ // oos.writeObject(world); // Remove those // oos.writeObject(OCTREE_ID.get()); // oos.writeObject(LwocMesh.MESH_ID.get()); // } } /** * Read input stream and deserialize it to world octree structure. * @param ois ObjectInputStream to read from * @throws ClassNotFoundException * @throws IOException */ private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { ois.defaultReadObject(); // now rebuild transient .parent and .world field for the whole tree lwoc_root.restoreWorldParent( this, // LwocWorld world, null); //LwocOctree parent) lwoc_root.rebuildMeshLists( true); // final boolean check_existed) } /** * Init worlds and their list. Multiple worlds may be needed if some world initially can not * be matched. They will grow independently and possibly merged later */ public static void initWorlds() { LwocMesh.resetMeshes(); LwocScene.resetScenes(); LwocOctree.resetPending(); lwoc_worlds = new ArrayList<LwocWorld>(); } /** * Create a new empty world and add it to the list of worlds in the universe. * @param center X,Y,Z of the new world * @param world_hsize new world half-size * @param min_hsize do not subdivide nodes if half-size is smaller than this * @param max_hsize do not grow world if its half-size it >= this * @param max_mesh_centers maximal number of mesh centers in a node to trigger subdivision * @param max_cameras maximal number of scenes (cameras) in a node to trigger subdivision * @param atr world rotation relative to the universe (non-null when defined) * @param xyz world offset in the universe (non-null when defined) * @return new world instance */ public static LwocWorld newWorld( double [] center, double world_hsize, double min_hsize, double max_hsize, int max_mesh_centers, int max_cameras, double [] atr, double [] xyz) { LwocWorld new_world = new LwocWorld ( min_hsize, // double min_hsize, max_hsize, // double max_hsize, max_mesh_centers, // int max_mesh_centers, max_cameras, // int max_cameras, null, // LwocOctree lwoc_root, null, //double [] atr, null); //double [] xyz); LwocOctree root_node = new LwocOctree ( new_world, // LwocWorld lwocWorld, null, // LwocOctree parent, center, // double [] xyz, world_hsize); //double hsize) root_node.leaf = new LwocLeaf(); new_world.setLwocRoot(root_node); lwoc_worlds.add(new_world); return new_world; } /** * Delete world from the universe (if existed) * @param world world instance to remove * @return True if removed, false if did not exist. */ public static boolean deleteWorld (LwocWorld world) { return lwoc_worlds.remove(world); } } Loading
src/main/java/com/elphel/imagej/tileprocessor/lwoc/LwocMesh.java +4 −4 Original line number Original line Diff line number Diff line Loading @@ -25,11 +25,11 @@ package com.elphel.imagej.tileprocessor.lwoc; package com.elphel.imagej.tileprocessor.lwoc; import java.io.Serializable; import java.io.Serializable; import java.util.concurrent.atomic.AtomicInteger; ///import java.util.concurrent.atomic.AtomicInteger; public class LwocMesh implements Serializable { public class LwocMesh implements Serializable { private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L; static AtomicInteger MESH_ID = new AtomicInteger(); /// static AtomicInteger MESH_ID = new AtomicInteger(); // static ArrayList<LwocMesh> LWOC_MESHES; // static ArrayList<LwocMesh> LWOC_MESHES; int id; // assign unique ID int id; // assign unique ID String stimestamp; // mesh is always referenced to a single scene String stimestamp; // mesh is always referenced to a single scene Loading @@ -37,7 +37,7 @@ public class LwocMesh implements Serializable { double [] hdims_xyz; // world bounding box half-dimensions along x,y,z double [] hdims_xyz; // world bounding box half-dimensions along x,y,z public static void resetMeshes() { public static void resetMeshes() { MESH_ID.set(0); /// MESH_ID.set(0); // LWOC_MESHES = new ArrayList<LwocMesh>(); // LWOC_MESHES = new ArrayList<LwocMesh>(); } } // maybe use mesh properties instead of id? // maybe use mesh properties instead of id? Loading @@ -48,7 +48,7 @@ public class LwocMesh implements Serializable { String stimestamp String stimestamp ) { ) { this.stimestamp = stimestamp; this.stimestamp = stimestamp; id = MESH_ID.getAndIncrement(); /// id = MESH_ID.getAndIncrement(); // LWOC_MESHES.add(this); // LWOC_MESHES.add(this); } } Loading
src/main/java/com/elphel/imagej/tileprocessor/lwoc/LwocOctree.java +83 −147 Original line number Original line Diff line number Diff line Loading @@ -24,11 +24,11 @@ package com.elphel.imagej.tileprocessor.lwoc; package com.elphel.imagej.tileprocessor.lwoc; import java.io.FileInputStream; //import java.io.FileInputStream; import java.io.FileOutputStream; //import java.io.FileOutputStream; import java.io.IOException; //import java.io.IOException; import java.io.ObjectInputStream; //import java.io.ObjectInputStream; import java.io.ObjectOutputStream; //import java.io.ObjectOutputStream; import java.io.Serializable; import java.io.Serializable; import java.util.ArrayList; import java.util.ArrayList; import java.util.List; import java.util.List; Loading @@ -37,99 +37,21 @@ import com.elphel.imagej.common.MultiThreading; public class LwocOctree implements Serializable { public class LwocOctree implements Serializable { private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L; public static final int NUM_CHILDREN = 8; public static final int NUM_CHILDREN = 8; public static double MIN_HSIZE = 0.3; // meter - do not subdivide more // static AtomicInteger OCTREE_ID = new AtomicInteger(); // can not be used as intersecting meshes' bb will not decrease number after splitting public static int MAX_MESH_CENTERS = 10; // maximal number of meshes in a leaf; public static int MAX_CAMERAS = 10; // maximal number of cameras in a leaf; public static LwocOctree lwoc_root = null; // static ArrayList<LwocOctree> LWOK_OCTREE = new ArrayList<LwocOctree>(); static AtomicInteger OCTREE_ID = new AtomicInteger(); static List<LwocScene> pendingScenes; // synchronized - add not-yet-added scenes pending growing world static List<LwocScene> pendingScenes; // synchronized - add not-yet-added scenes pending growing world static List<LwocMesh> pendingMeshes; // synchronized - add not-yet-added meshes pending growing world static List<LwocMesh> pendingMeshes; // synchronized - add not-yet-added meshes pending growing world static List<LwocOctree> pendingLeafNodes;// synchronized - leaf nodes needed to be split static List<LwocOctree> pendingLeafNodes;// synchronized - leaf nodes needed to be split // static List<LwocWorld> lwoc_worlds; // int id; // assign unique ID int id; // assign unique ID LwocOctree parent; transient LwocWorld world; transient LwocOctree parent; LwocOctree [] children; LwocOctree [] children; LwocLeaf leaf; // LwocLeaf leaf; // double [] center; // x-center, y-center, z-center double [] center; // x-center, y-center, z-center double hsize; double hsize; /** * Serialize and write world to an output stream * @param oos ObjectOutputStream to write to. * @throws IOException */ private void writeObject(ObjectOutputStream oos) throws IOException { oos.defaultWriteObject(); if (parent == null) { // write static members oos.writeObject(MIN_HSIZE); oos.writeObject(MAX_MESH_CENTERS); oos.writeObject(MAX_CAMERAS); oos.writeObject(OCTREE_ID.get()); oos.writeObject(LwocMesh.MESH_ID.get()); } } /** * Read input stream and deserialize it to world octree structure. * @param ois ObjectInputStream to read from * @throws ClassNotFoundException * @throws IOException */ private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { ois.defaultReadObject(); if (parent == null) { // read static members MIN_HSIZE = (Double) ois.readObject(); MAX_MESH_CENTERS = (Integer) ois.readObject(); MAX_CAMERAS = (Integer) ois.readObject(); OCTREE_ID.set( (Integer) ois.readObject()); LwocMesh.MESH_ID.set((Integer) ois.readObject()); } } /** * * @param path */ public static void saveWorld(String path) { try { FileOutputStream fileOut = new FileOutputStream(path); ObjectOutputStream out = new ObjectOutputStream(fileOut); out.writeObject(lwoc_root); // will cause all world to be saved out.close(); fileOut.close(); System.out.printf("Serialized data is saved in "+path); } catch (IOException e) { e.printStackTrace(); } } public static void restoreWorld(String path) { try { FileInputStream fileIn = new FileInputStream(path); ObjectInputStream in = new ObjectInputStream(fileIn); lwoc_root = (LwocOctree) in.readObject(); in.close(); fileIn.close(); } catch (IOException e) { e.printStackTrace(); return; } catch (ClassNotFoundException c) { System.out.println(path+" not found"); c.printStackTrace(); return; } } public static void addPendingScene(LwocScene scene) { public static void addPendingScene(LwocScene scene) { synchronized(pendingScenes) { synchronized(pendingScenes) { pendingScenes.add(scene); pendingScenes.add(scene); Loading @@ -148,22 +70,6 @@ public class LwocOctree implements Serializable { } } } } /** * Initialize Octree data and set initial world node. It is possible to grow * world as needed later. * @param center world center: x,y,z in meters. Usually {0,0,0} * @param world_hsize Half linear dimension of the world */ public static void initOctree(double [] center, double world_hsize) { LwocMesh.resetMeshes(); LwocScene.resetScenes(); resetPending(); // LWOK_OCTREE = new ArrayList<LwocOctree>(); // Add a single leaf node lwoc_root = new LwocOctree(null, center, world_hsize); lwoc_root.leaf = new LwocLeaf(); } /** /** * Synchronized lists of pending scenes, meshes and nodes are used to delay modification of * Synchronized lists of pending scenes, meshes and nodes are used to delay modification of * the world octree and its elements from the multithreaded environment. These lists should * the world octree and its elements from the multithreaded environment. These lists should Loading Loading @@ -202,18 +108,19 @@ public class LwocOctree implements Serializable { /** /** * LwocOctree constructor * LwocOctree constructor * @param lwocWorld World global parameters * @param parent Parent node * @param parent Parent node * @param xyz position of the node center in meters * @param xyz Position of the node center in meters * @param hsize Node half size - each of the X,Y,Z coordinates of the internal * @param hsize Node half size - each of the X,Y,Z coordinates of the internal * points are limited within +/-hsize from the node center * points are limited within +/-hsize from the node center */ */ public LwocOctree (LwocOctree parent, public LwocOctree ( LwocWorld lwocWorld, LwocOctree parent, double [] xyz, double [] xyz, double hsize) { double hsize) { id = OCTREE_ID.getAndIncrement(); this.parent = parent; this.parent = parent; this.hsize = hsize; this.hsize = hsize; // LWOK_OCTREE.add(this); } } /** /** Loading @@ -222,14 +129,15 @@ public class LwocOctree implements Serializable { * @return Octree node that includes the point or null if the point * @return Octree node that includes the point or null if the point * is outside the root node (the whole world) * is outside the root node (the whole world) */ */ public static LwocOctree getLeafNode( // if null - needs growing world //FIXME: obey border (on the edges of max hsize of the root) nodes public LwocOctree getLeafNode( // if null - needs growing world double [] xyz) { // thread safe double [] xyz) { // thread safe if (!lwoc_root.contains(xyz)) return null; // needs growing world if (!world.getLwocRoot().contains(xyz)) return null; // needs growing world LwocOctree node = lwoc_root; LwocOctree node = world.getLwocRoot(); while (lwoc_root.children != null) { while (world.getLwocRoot().children != null) { int indx = 0; int indx = 0; for (int dm = 0; dm < 3; dm++) { for (int dm = 0; dm < 3; dm++) { if (xyz[dm] >= lwoc_root.center[dm] ) { if (xyz[dm] >= world.getLwocRoot().center[dm] ) { indx += 1 << dm; indx += 1 << dm; } } } } Loading @@ -245,7 +153,7 @@ public class LwocOctree implements Serializable { * @param check_existed - do not add duplicate scenes and nodes * @param check_existed - do not add duplicate scenes and nodes * @return An octree node where scene is added or null if the world needs growing * @return An octree node where scene is added or null if the world needs growing */ */ public static LwocOctree addScene( public LwocOctree addScene( LwocScene scene, LwocScene scene, boolean check_existed boolean check_existed ) {// returns null and adds to pendingScenes if needs growing ) {// returns null and adds to pendingScenes if needs growing Loading @@ -259,8 +167,8 @@ public class LwocOctree implements Serializable { } else { } else { node.leaf.addScene(scene,check_existed); node.leaf.addScene(scene,check_existed); // Check if leaf node requires splitting // Check if leaf node requires splitting if (node.leaf.getScenes().size() > MAX_CAMERAS) { if (node.leaf.getScenes().size() > world.getMaxCameras()) { if (node.hsize > MIN_HSIZE) { if (node.hsize > world.getMinHsize()) { if (!check_existed || !pendingLeafNodes.contains(node)) { if (!check_existed || !pendingLeafNodes.contains(node)) { addPendingLeafNode(node); addPendingLeafNode(node); } } Loading @@ -274,7 +182,7 @@ public class LwocOctree implements Serializable { * Tend to pending scenes list. Not thread-safe, should be run in a single-thread mode. * Tend to pending scenes list. Not thread-safe, should be run in a single-thread mode. * @param check_existed - do not add duplicate scenes and nodes * @param check_existed - do not add duplicate scenes and nodes */ */ public static void tendPendingScenes( public void tendPendingScenes( boolean check_existed boolean check_existed ) { ) { if (pendingScenes.isEmpty()) { if (pendingScenes.isEmpty()) { Loading @@ -295,7 +203,7 @@ public class LwocOctree implements Serializable { * Only adds mesh centers and grows the world if needed. * Only adds mesh centers and grows the world if needed. * @param check_existed do not add duplicate meshes * @param check_existed do not add duplicate meshes */ */ public static void tendPendingMeshCentersOnly( public void tendPendingMeshCentersOnly( boolean check_existed boolean check_existed ) { ) { if (pendingMeshes.isEmpty()) { if (pendingMeshes.isEmpty()) { Loading Loading @@ -326,14 +234,14 @@ public class LwocOctree implements Serializable { * Should be run after tendPendingMeshCentersOnly(). * Should be run after tendPendingMeshCentersOnly(). * @param check_existed do not add duplicate meshes * @param check_existed do not add duplicate meshes */ */ public static void tendPendingMeshes( public void tendPendingMeshes( boolean check_existed ) { boolean check_existed ) { if (pendingMeshes.isEmpty()) { if (pendingMeshes.isEmpty()) { return; // nothing to do return; // nothing to do } else { } else { for (LwocMesh mesh: pendingMeshes) { for (LwocMesh mesh: pendingMeshes) { // int num_added = // int num_added = lwoc_root.addMesh( world.lwoc_root.addMesh( mesh, mesh, check_existed); check_existed); } } Loading Loading @@ -417,6 +325,7 @@ public class LwocOctree implements Serializable { xyz[dm] +=new_hsize * ((((nchild >> dm) & 1) > 0)? 1 : -1); xyz[dm] +=new_hsize * ((((nchild >> dm) & 1) > 0)? 1 : -1); } } children[nchild] = new LwocOctree( children[nchild] = new LwocOctree( world, this, this, xyz, xyz, new_hsize); new_hsize); Loading Loading @@ -481,41 +390,44 @@ public class LwocOctree implements Serializable { * until the specified point gets inside. Not thread safe, should run in single-thread mode * until the specified point gets inside. Not thread safe, should run in single-thread mode * @param xyz The point to be included in the world. * @param xyz The point to be included in the world. */ */ public static void growXYZ(double [] xyz) { public void growXYZ(double [] xyz) { while (!lwoc_root.contains(xyz)) {// already fits, do not grow while (!world.lwoc_root.contains(xyz)) {// already fits, do not grow // grow once // grow once int indx=0; //direction to grow int indx=0; //direction to grow double [] new_center = new double[3]; double [] new_center = new double[3]; double [] root_center = world.lwoc_root.center; double root_hsize = world.lwoc_root.hsize; for (int dm = 0; dm < new_center.length; dm++) { for (int dm = 0; dm < new_center.length; dm++) { if (xyz[dm] >= lwoc_root.center[dm] ) { if (xyz[dm] >= root_center[dm] ) { indx += 1 << dm; indx += 1 << dm; new_center[dm]= lwoc_root.center[dm] + lwoc_root.hsize; new_center[dm]= root_center[dm] + root_hsize; } else { } else { new_center[dm]= lwoc_root.center[dm] - lwoc_root.hsize; new_center[dm]= root_center[dm] - root_hsize; } } } } LwocOctree new_root = new LwocOctree(null, new_center, lwoc_root.hsize * 2); LwocOctree new_root = new LwocOctree(world,null, new_center, world.lwoc_root.hsize * 2); new_root.children = new LwocOctree[NUM_CHILDREN]; new_root.children = new LwocOctree[NUM_CHILDREN]; int child = (~indx ) & (NUM_CHILDREN -1); // opposite direction, from new root to old root int child = (~indx ) & (NUM_CHILDREN -1); // opposite direction, from new root to old root for (int ichild = 0; ichild < NUM_CHILDREN; ichild++) { for (int ichild = 0; ichild < NUM_CHILDREN; ichild++) { if (ichild == child) { if (ichild == child) { lwoc_root.parent = new_root; world.lwoc_root.parent = new_root; new_root.children[ichild] = lwoc_root; new_root.children[ichild] = world.lwoc_root; } else { // create empty leaf nodes } else { // create empty leaf nodes new_root.children[ichild] = new LwocOctree( new_root.children[ichild] = new LwocOctree( world, new_root, new_root, new double [] { new double [] { new_center[0] + lwoc_root.hsize * ((((child >> 0) & 1) > 0)? 1 : -1), new_center[0] + root_hsize * ((((child >> 0) & 1) > 0)? 1 : -1), new_center[1] + lwoc_root.hsize * ((((child >> 1) & 1) > 0)? 1 : -1), new_center[1] + root_hsize * ((((child >> 1) & 1) > 0)? 1 : -1), new_center[2] + lwoc_root.hsize * ((((child >> 2) & 1) > 0)? 1 : -1) new_center[2] + root_hsize * ((((child >> 2) & 1) > 0)? 1 : -1) }, }, lwoc_root.hsize); root_hsize); // add leaf // add leaf new_root.children[ichild].leaf = new LwocLeaf(); new_root.children[ichild].leaf = new LwocLeaf(); } } } } lwoc_root = new_root; world.lwoc_root = new_root; } } } } Loading @@ -525,6 +437,7 @@ public class LwocOctree implements Serializable { * @param half_whd half width(x), height(y) and depth(z) * @param half_whd half width(x), height(y) and depth(z) * @return True if it intersects * @return True if it intersects */ */ //FIXME: obey border (on the edges of max hsize of the root) nodes public boolean intersects ( public boolean intersects ( double [] xyz, double [] xyz, double [] half_whd) { double [] half_whd) { Loading @@ -544,6 +457,7 @@ public class LwocOctree implements Serializable { * @param xyz point * @param xyz point * @return True if it intersects * @return True if it intersects */ */ //FIXME: obey border (on the edges of max hsize of the root) nodes public boolean contains ( public boolean contains ( double [] xyz) { double [] xyz) { for (int dm = 0; dm < center.length; dm++) { for (int dm = 0; dm < center.length; dm++) { Loading @@ -563,6 +477,8 @@ public class LwocOctree implements Serializable { * @param half_whd half width(x), height(y) and depth(z) * @param half_whd half width(x), height(y) and depth(z) * @return True if it intersects * @return True if it intersects */ */ //FIXME: obey border (on the edges of max hsize of the root) nodes public boolean contains ( public boolean contains ( double [] xyz, double [] xyz, double [] half_whd) { double [] half_whd) { Loading @@ -584,7 +500,7 @@ public class LwocOctree implements Serializable { * @param check_existed Add only if the same mesh did not exist * @param check_existed Add only if the same mesh did not exist * @return number of nodes it was added to (intersecting) * @return number of nodes it was added to (intersecting) */ */ public static boolean addMeshCenter( // returns 0 and adds to pendingMeshes if needs growing public boolean addMeshCenter( // returns 0 and adds to pendingMeshes if needs growing LwocMesh mesh, LwocMesh mesh, boolean check_existed boolean check_existed ) { ) { Loading @@ -594,7 +510,7 @@ public class LwocOctree implements Serializable { double [] corner_xyz = center.clone(); double [] corner_xyz = center.clone(); for (int dm = 0; dm < center.length; dm++) { for (int dm = 0; dm < center.length; dm++) { corner_xyz[dm] += dims[dm]; corner_xyz[dm] += dims[dm]; if (!lwoc_root.contains(corner_xyz)){ if (!world.lwoc_root.contains(corner_xyz)){ if (pendingMeshes != null) { if (pendingMeshes != null) { if (!check_existed || !pendingMeshes.contains(mesh)) { if (!check_existed || !pendingMeshes.contains(mesh)) { addPendingMesh(mesh); addPendingMesh(mesh); Loading @@ -603,7 +519,7 @@ public class LwocOctree implements Serializable { return false; return false; } } corner_xyz[dm] -= 2*dims[dm]; corner_xyz[dm] -= 2*dims[dm]; if (!lwoc_root.contains(corner_xyz)){ if (!world.lwoc_root.contains(corner_xyz)){ if (pendingMeshes != null) { if (pendingMeshes != null) { if (!check_existed || !pendingMeshes.contains(mesh)) { if (!check_existed || !pendingMeshes.contains(mesh)) { addPendingMesh(mesh); addPendingMesh(mesh); Loading @@ -617,8 +533,8 @@ public class LwocOctree implements Serializable { LwocOctree node = getLeafNode(center); LwocOctree node = getLeafNode(center); node.leaf.addMeshCenter(mesh, check_existed); node.leaf.addMeshCenter(mesh, check_existed); // Check if leaf node requires splitting // Check if leaf node requires splitting if (node.leaf.getMeshCenters().size() > MAX_MESH_CENTERS) { if (node.leaf.getMeshCenters().size() > world.getMaxMeshCenters()) { if (node.hsize > MIN_HSIZE) { if (node.hsize > world.getMinHsize()) { if (!check_existed || !pendingLeafNodes.contains(node)) { if (!check_existed || !pendingLeafNodes.contains(node)) { addPendingLeafNode(node); addPendingLeafNode(node); } } Loading Loading @@ -659,7 +575,7 @@ public class LwocOctree implements Serializable { * Should fit in a root node (as it was earlier added) * Should fit in a root node (as it was earlier added) * @param mesh new mesh to add * @param mesh new mesh to add */ */ public static void removeMeshCenter( public void removeMeshCenter( LwocMesh mesh) { // check and remove duplicates LwocMesh mesh) { // check and remove duplicates LwocOctree node = getLeafNode(mesh.getCenter()); LwocOctree node = getLeafNode(mesh.getCenter()); node.leaf.removeMeshCenter(mesh); node.leaf.removeMeshCenter(mesh); Loading Loading @@ -688,6 +604,26 @@ public class LwocOctree implements Serializable { return removed; return removed; } } /** * Restore pointers to .parent and .world * @param world * @param parent */ public void restoreWorldParent( LwocWorld world, LwocOctree parent) { this.parent = parent; this.world = world; if (!isLeaf()) { for (LwocOctree child:children) { child.restoreWorldParent( world, // LwocWorld world, this); // LwocOctree parent) } } } /** /** * Recursively create a list of all leave nodes in the world. * Recursively create a list of all leave nodes in the world. * @return A list of all leaf nodes * @return A list of all leaf nodes Loading @@ -708,9 +644,9 @@ public class LwocOctree implements Serializable { * Rebuild meshes lists from mesh_centers for all leaf nodes after restoring the world. * Rebuild meshes lists from mesh_centers for all leaf nodes after restoring the world. * Used after restoring world from serialized form * Used after restoring world from serialized form */ */ public static void rebuildMeshLists( public void rebuildMeshLists( final boolean check_existed) { final boolean check_existed) { final List<LwocOctree> leaves = lwoc_root.getAllLeafNodes(); final List<LwocOctree> leaves = world.lwoc_root.getAllLeafNodes(); final List<LwocMesh> meshes = new ArrayList<LwocMesh>(); final List<LwocMesh> meshes = new ArrayList<LwocMesh>(); for (LwocOctree node : leaves) { for (LwocOctree node : leaves) { node.leaf.initMeshes(); node.leaf.initMeshes(); Loading @@ -726,7 +662,7 @@ public class LwocOctree implements Serializable { public void run() { public void run() { for (int indx_mesh = ai.getAndIncrement(); indx_mesh < meshes.size(); indx_mesh = ai.getAndIncrement()) { for (int indx_mesh = ai.getAndIncrement(); indx_mesh < meshes.size(); indx_mesh = ai.getAndIncrement()) { LwocMesh mesh = meshes.get(indx_mesh); LwocMesh mesh = meshes.get(indx_mesh); lwoc_root.addMesh(mesh, check_existed); world.lwoc_root.addMesh(mesh, check_existed); } } } } }; }; Loading
src/main/java/com/elphel/imagej/tileprocessor/lwoc/LwocWorld.java 0 → 100644 +187 −0 Original line number Original line Diff line number Diff line /** ** ** LwocWorld.java - Octree world parameters (previous static) ** ** Copyright (C) 2022 Elphel, Inc. ** ** -----------------------------------------------------------------------------** ** ** LwocWorld.java is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see <http://www.gnu.org/licenses/>. ** -----------------------------------------------------------------------------** ** */ package com.elphel.imagej.tileprocessor.lwoc; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.List; public class LwocWorld implements Serializable { private static final long serialVersionUID = 1L; static List<LwocWorld> lwoc_worlds; // public double min_hsize; // = 0.3; // meter - do not subdivide more public double max_hsize; // = 10000.0; // meter - do not grow more public int max_mesh_centers; // = 10; // maximal number of meshes in a leaf; public int max_cameras; // = 10; // maximal number of cameras in a leaf; // public transient LwocOctree lwoc_root; // = null; public LwocOctree lwoc_root; // = null; public double [] atr; // = null; // Azimuth, tilt, roll - may be used to merge public double [] xyz; // = null; // this world offset (before rotation) or // null if not known. public LwocWorld ( double min_hsize, double max_hsize, int max_mesh_centers, int max_cameras, LwocOctree lwoc_root, double [] atr, double [] xyz) { setMinHsize (min_hsize); setMaxHsize (max_hsize); setMaxMeshCenters(max_mesh_centers); setMaxCameras (max_cameras); setLwocRoot (lwoc_root); setATR (atr); setXYZ (xyz); } public double getMinHsize() {return min_hsize;} public double getMaxHsize() {return max_hsize;} public int getMaxMeshCenters() {return max_mesh_centers;} public int getMaxCameras() {return max_cameras;} public LwocOctree getLwocRoot() {return lwoc_root;} public double [] getATR() {return atr;} public double [] getXYZ() {return xyz;} public void setMinHsize (double min_hsize) {this.min_hsize = min_hsize;} public void setMaxHsize (double max_hsize) {this.max_hsize = max_hsize;} public void setMaxMeshCenters(int max_mesh_centers) {this.max_mesh_centers = max_mesh_centers;} public void setMaxCameras (int max_cameras) {this.max_cameras = max_cameras;} public void setLwocRoot (LwocOctree lwoc_root) {this.lwoc_root = lwoc_root;} public void setATR (double [] atr) {this.atr = atr;} public void setXYZ (double [] xyz) {this.xyz = xyz;} /** * Serialize and write world to an output stream * @param oos ObjectOutputStream to write to. * @throws IOException */ private void writeObject(ObjectOutputStream oos) throws IOException { oos.defaultWriteObject(); // as of now - nothing else, custom for reads only // if (parent == null) { // write world members /* oos.writeObject(world.getMinHsize()); oos.writeObject(world.getMaxHsize()); oos.writeObject(world.getMaxMeshCenters()); oos.writeObject(world.getMaxCameras()); oos.writeObject(world.getATR()); oos.writeObject(world.getXYZ()); */ // oos.writeObject(world); // Remove those // oos.writeObject(OCTREE_ID.get()); // oos.writeObject(LwocMesh.MESH_ID.get()); // } } /** * Read input stream and deserialize it to world octree structure. * @param ois ObjectInputStream to read from * @throws ClassNotFoundException * @throws IOException */ private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { ois.defaultReadObject(); // now rebuild transient .parent and .world field for the whole tree lwoc_root.restoreWorldParent( this, // LwocWorld world, null); //LwocOctree parent) lwoc_root.rebuildMeshLists( true); // final boolean check_existed) } /** * Init worlds and their list. Multiple worlds may be needed if some world initially can not * be matched. They will grow independently and possibly merged later */ public static void initWorlds() { LwocMesh.resetMeshes(); LwocScene.resetScenes(); LwocOctree.resetPending(); lwoc_worlds = new ArrayList<LwocWorld>(); } /** * Create a new empty world and add it to the list of worlds in the universe. * @param center X,Y,Z of the new world * @param world_hsize new world half-size * @param min_hsize do not subdivide nodes if half-size is smaller than this * @param max_hsize do not grow world if its half-size it >= this * @param max_mesh_centers maximal number of mesh centers in a node to trigger subdivision * @param max_cameras maximal number of scenes (cameras) in a node to trigger subdivision * @param atr world rotation relative to the universe (non-null when defined) * @param xyz world offset in the universe (non-null when defined) * @return new world instance */ public static LwocWorld newWorld( double [] center, double world_hsize, double min_hsize, double max_hsize, int max_mesh_centers, int max_cameras, double [] atr, double [] xyz) { LwocWorld new_world = new LwocWorld ( min_hsize, // double min_hsize, max_hsize, // double max_hsize, max_mesh_centers, // int max_mesh_centers, max_cameras, // int max_cameras, null, // LwocOctree lwoc_root, null, //double [] atr, null); //double [] xyz); LwocOctree root_node = new LwocOctree ( new_world, // LwocWorld lwocWorld, null, // LwocOctree parent, center, // double [] xyz, world_hsize); //double hsize) root_node.leaf = new LwocLeaf(); new_world.setLwocRoot(root_node); lwoc_worlds.add(new_world); return new_world; } /** * Delete world from the universe (if existed) * @param world world instance to remove * @return True if removed, false if did not exist. */ public static boolean deleteWorld (LwocWorld world) { return lwoc_worlds.remove(world); } }