def test_door_setup(self):
        parent_np = NodePath('parent_np')
        parent_np.setPosHpr(0, 10, .5, 180, 0, 0)

        door_origin = parent_np.attachNewNode('door_origin')
        door_origin.setPos(10, -25, .5)

        block = 4
        color = Vec4(.842, .167, .361, 1)

        # Set up door_np nodes
        door_np = NodePath('door_np')

        left_hole = door_np.attachNewNode('door_0_hole_left')
        right_hole = door_np.attachNewNode('door_0_hole_right')

        left_door = door_np.attachNewNode('door_0_left')
        right_door = door_np.attachNewNode('door_0_right')

        door_flat = door_np.attachNewNode('door_0_flat')
        door_trigger = door_np.attachNewNode('door_0_trigger')

        DNADoor.setupDoor(door_np, parent_np, door_origin, self.store, block, color)

        # Check if the nodes attributes and parents are correct
        self.assertEqual(door_np.getPos(door_origin), Point3(0, 0, 0))
        self.assertEqual(door_np.getHpr(door_origin), Point3(0, 0, 0))
        self.assertEqual(door_np.getScale(door_origin), Point3(1, 1, 1))

        def verify_color(color1, color2):
            self.assertAlmostEqual(color1.getX(), color2.getX(), places=4)
            self.assertAlmostEqual(color1.getY(), color2.getY(), places=4)
            self.assertAlmostEqual(color1.getZ(), color2.getZ(), places=4)
            self.assertAlmostEqual(color1.getW(), color2.getW(), places=4)

        verify_color(color, door_np.getColor())

        self.assertEqual(left_hole.getParent(), door_flat)
        self.assertEqual(left_hole.getName(), 'doorFrameHoleLeft')

        self.assertEqual(right_hole.getParent(), door_flat)
        self.assertEqual(right_hole.getName(), 'doorFrameHoleRight')

        self.assertEqual(left_door.getParent(), parent_np)
        self.assertEqual(left_door.getName(), 'leftDoor')
        verify_color(color, right_door.getColor())

        self.assertEqual(right_door.getParent(), parent_np)
        self.assertEqual(right_door.getName(), 'rightDoor')
        verify_color(color, right_door.getColor())

        self.assertEqual(door_trigger.getParent(), parent_np)
        self.assertEqual(door_trigger.getName(), 'door_trigger_%d' % block)

        store_np = self.store.getDoorPosHprFromBlockNumber(block)
        self.assertFalse(store_np.isEmpty())

        # Testing the pos is a pain because of decimal precision
        pos = store_np.getPos()
        self.assertAlmostEqual(pos.getX(), -10, places=2)
        self.assertAlmostEqual(pos.getY(), 35, places=2)
        self.assertAlmostEqual(pos.getZ(), 1, places=2)

        # Sometimes getH() returns -180 and others 180
        # Test the modulus (better than abs I guess)
        self.assertEqual(store_np.getH() % 180, 0)
Пример #2
0
class StaticGeometricModel(object):
    """
    load an object as a static geometric model -> changing pos, rot, color, etc. are not allowed
    there is no extra elements for this model, thus is much faster
    author: weiwei
    date: 20190312
    """
    def __init__(self,
                 initor=None,
                 name="defaultname",
                 btransparency=True,
                 btwosided=False):
        """
        :param initor: path type defined by os.path or trimesh or nodepath
        :param btransparency
        :param name
        """
        if isinstance(initor, StaticGeometricModel):
            self._objpath = copy.deepcopy(initor.objpath)
            self._objtrm = copy.deepcopy(initor.objtrm)
            self._objpdnp = copy.deepcopy(initor.objpdnp)
            self._name = copy.deepcopy(initor.name)
            self._localframe = copy.deepcopy(initor.localframe)
        else:
            # make a grandma nodepath to separate decorations (-autoshader) and raw nodepath (+autoshader)
            self._name = name
            self._objpdnp = NodePath(name)
            if isinstance(initor, str):
                self._objpath = initor
                self._objtrm = da.trm.load(self._objpath)
                objpdnp_raw = da.trimesh_to_nodepath(self._objtrm,
                                                     name='pdnp_raw')
                objpdnp_raw.reparentTo(self._objpdnp)
            elif isinstance(initor, da.trm.Trimesh):
                self._objpath = None
                self._objtrm = initor
                objpdnp_raw = da.trimesh_to_nodepath(self._objtrm)
                objpdnp_raw.reparentTo(self._objpdnp)
            elif isinstance(initor, o3d.geometry.PointCloud
                            ):  # TODO should pointcloud be pdnp or pdnp_raw
                self._objpath = None
                self._objtrm = da.trm.Trimesh(np.asarray(initor.points))
                objpdnp_raw = da.nodepath_from_points(self._objtrm.vertices,
                                                      name='pdnp_raw')
                objpdnp_raw.reparentTo(self._objpdnp)
            elif isinstance(
                    initor,
                    np.ndarray):  # TODO should pointcloud be pdnp or pdnp_raw
                self._objpath = None
                if initor.shape[1] == 3:
                    self._objtrm = da.trm.Trimesh(initor)
                    objpdnp_raw = da.nodepath_from_points(
                        self._objtrm.vertices)
                elif initor.shape[1] == 7:
                    self._objtrm = da.trm.Trimesh(initor[:, :3])
                    objpdnp_raw = da.nodepath_from_points(
                        self._objtrm.vertices, initor[:, 3:].tolist())
                    objpdnp_raw.setRenderMode(RenderModeAttrib.MPoint, 3)
                else:
                    # TODO depth UV?
                    raise NotImplementedError
                objpdnp_raw.reparentTo(self._objpdnp)
            elif isinstance(initor, o3d.geometry.TriangleMesh):
                self._objpath = None
                self._objtrm = da.trm.Trimesh(
                    vertices=initor.vertices,
                    faces=initor.triangles,
                    face_normals=initor.triangle_normals)
                objpdnp_raw = da.trimesh_to_nodepath(self._objtrm,
                                                     name='pdnp_raw')
                objpdnp_raw.reparentTo(self._objpdnp)
            elif isinstance(initor, NodePath):
                self._objpath = None
                self._objtrm = None  # TODO nodepath to trimesh?
                objpdnp_raw = initor
                objpdnp_raw.reparentTo(self._objpdnp)
            else:
                self._objpath = None
                self._objtrm = None
                objpdnp_raw = NodePath("pdnp_raw")
                objpdnp_raw.reparentTo(self._objpdnp)
            if btransparency:
                self._objpdnp.setTransparency(TransparencyAttrib.MDual)
            if btwosided:
                self._objpdnp.getChild(0).setTwoSided(True)
            self._localframe = None

    @property
    def name(self):
        # read-only property
        return self._name

    @property
    def objpath(self):
        # read-only property
        return self._objpath

    @property
    def objpdnp(self):
        # read-only property
        return self._objpdnp

    @property
    def objpdnp_raw(self):
        # read-only property
        return self._objpdnp.getChild(0)

    @property
    def objtrm(self):
        # read-only property
        # 20210328 comment out, allow None
        # if self._objtrm is None:
        #     raise ValueError("Only applicable to models with a trimesh!")
        return self._objtrm

    @property
    def localframe(self):
        # read-only property
        return self._localframe

    @property
    def volume(self):
        # read-only property
        if self._objtrm is None:
            raise ValueError("Only applicable to models with a trimesh!")
        return self._objtrm.volume

    def set_rgba(self, rgba):
        self._objpdnp.setColor(rgba[0], rgba[1], rgba[2], rgba[3])

    def get_rgba(self):
        return da.pdv4_to_npv4(
            self._objpdnp.getColor())  # panda3d.core.LColor -> LBase4F

    def clear_rgba(self):
        self._objpdnp.clearColor()

    def set_scale(self, scale=[1, 1, 1]):
        self._objpdnp.setScale(scale[0], scale[1], scale[2])
        self._objtrm.apply_scale(scale)

    def get_scale(self):
        return da.pdv3_to_npv3(self._objpdnp.getScale())

    def set_vert_size(self, size=.005):
        self.objpdnp_raw.setRenderModeThickness(size * 1000)

    def attach_to(self, obj):
        if isinstance(obj, ShowBase):
            # for rendering to base.render
            self._objpdnp.reparentTo(obj.render)
        elif isinstance(obj, StaticGeometricModel
                        ):  # prepared for decorations like local frames
            self._objpdnp.reparentTo(obj.objpdnp)
        elif isinstance(obj, mc.ModelCollection):
            obj.add_gm(self)
        else:
            print(
                "Must be ShowBase, modeling.StaticGeometricModel, GeometricModel, CollisionModel, or CollisionModelCollection!"
            )

    def detach(self):
        self._objpdnp.detachNode()

    def remove(self):
        self._objpdnp.removeNode()

    def show_localframe(self):
        self._localframe = gen_frame()
        self._localframe.attach_to(self)

    def unshow_localframe(self):
        if self._localframe is not None:
            self._localframe.remove()
            self._localframe = None

    def copy(self):
        return copy.deepcopy(self)