class NodeModel implements Model, TextModel {

    protected static final long ONEOVERPHI = 106039;
    protected final Node node;
    public int markTime;
    public boolean mark;
    protected float cameraDistance;
    protected float[] dragDistance;
    //Octant
    protected Octant octant;
    protected int octantId;
    //Flags
    protected boolean selected;
    protected boolean highlight;
    //Edges
    protected EdgeModel[] edges;
    protected int edgeLength;

    public NodeModel(Node node) {
        this.node = node;

        //Default
        dragDistance = new float[2];
        selected = false;
        mark = false;
        markTime = 0;

        //Edges
        edges = new EdgeModel[0];
    }

    public int octreePosition(float centerX, float centerY, float centerZ, float size) {<FILL_FUNCTION_BODY>}

    public boolean isInOctreeLeaf(Octant leaf) {
//        float radius = node.size() / 2f;
        if (Math.abs(node.x() - leaf.getPosX()) > (leaf.getSize() / 2)
            || Math.abs(node.y() - leaf.getPosY()) > (leaf.getSize() / 2)
            || Math.abs(node.z() - leaf.getPosZ()) > (leaf.getSize() / 2)) {
            return false;
        }
        return true;
    }

    public abstract boolean selectionTest(Vecf distanceFromMouse, float selectionSize);

    public abstract float getCollisionDistance(double angle);

    public Node getNode() {
        return node;
    }

    public float getCameraDistance() {
        return cameraDistance;
    }

    public void setCameraDistance(float cameraDistance) {
        this.cameraDistance = cameraDistance;
    }

    public float getX() {
        return node.x();
    }

    public float getY() {
        return node.y();
    }

    @Override
    public boolean isSelected() {
        return selected;
    }

    @Override
    public void setSelected(boolean selected) {
        this.selected = selected;
    }

    public boolean isHighlight() {
        return highlight;
    }

    public Octant getOctant() {
        return octant;
    }

    public void setOctant(Octant octant) {
        this.octant = octant;
    }

    public int getOctantId() {
        return octantId;
    }

    public void setOctantId(int octantId) {
        this.octantId = octantId;
    }

    @Override
    public boolean hasCustomTextColor() {
        return node.getTextProperties().getAlpha() > 0;
    }

    @Override
    public float getTextWidth() {
        return node.getTextProperties().getWidth();
    }

    @Override
    public float getTextHeight() {
        return node.getTextProperties().getWidth();
    }

    @Override
    public String getText() {
        return node.getTextProperties().getText();
    }

    @Override
    public void setText(String text) {
        node.getTextProperties().setText(text);
    }

    @Override
    public float getTextSize() {
        return node.getTextProperties().getSize();
    }

    @Override
    public float getTextR() {
        return node.getTextProperties().getR();
    }

    @Override
    public float getTextG() {
        return node.getTextProperties().getG();
    }

    @Override
    public float getTextB() {
        return node.getTextProperties().getB();
    }

    @Override
    public float getTextAlpha() {
        return node.getTextProperties().getAlpha();
    }

    @Override
    public boolean isTextVisible() {
        return node.getTextProperties().isVisible();
    }

    @Override
    public ElementProperties getElementProperties() {
        return node;
    }

    public float[] getDragDistanceFromMouse() {
        return dragDistance;
    }

    public void addEdge(EdgeModel model) {
        int id = edgeLength++;
        growEdges(id);
        edges[id] = model;
        if (model.getSourceModel() == this) {
            model.setOctantSourceId(id);
        } else {
            model.setOctantTargetId(id);
        }
    }

    public void removeEdge(EdgeModel model) {
        int id;
        if (model.getSourceModel() == this) {
            id = model.getOctantSourceId();
        } else {
            id = model.getOctantTargetId();
        }
        edges[id] = null;
    }

    public EdgeModel[] getEdges() {
        return edges;
    }

    private void growEdges(final int index) {
        if (index >= edges.length) {
            final int newLength =
                (int) Math.min(Math.max((ONEOVERPHI * edges.length) >>> 16, index + 1), Integer.MAX_VALUE);
            final EdgeModel t[] = new EdgeModel[newLength];
            System.arraycopy(edges, 0, t, 0, edges.length);
            edges = t;
        }
    }
}

        //float radius = obj.getRadius();
        int index = 0;

        if (node.y() < centerY) {
            index += 4;
        }
        if (node.z() > centerZ) {
            index += 2;
        }
        if (node.x() < centerX) {
            index += 1;
        }

        return index;
    
<no_super_class>