public RealLabelledData ortogonalProjection(LinProj p)
    {
        // Step one, calculating the transformation matrix:
        // TODO: this step should not be done here.
        double denom = 0;
        double[][] tmatrix = new double[p.w.length][p.w.length];
        for (int i = 0; i < p.w.length; i++)
        {
            denom += p.w[i] * p.w[i];
            for (int j = 0; j < p.w.length; j++)
            {
                tmatrix[i][j] = p.w[i]*p.w[j];
            }
        }

        for (int i = 0; i < p.w.length; i ++)
            for (int j = 0; j < p.w.length; j ++)
            {
                tmatrix[i][j] = - tmatrix[i][j]/denom;
                if (i==j)
                    tmatrix[i][j] = 1 + tmatrix[i][j];
            }

        // Step two: recalculating values for each point based on transformation matrix

        RealLabelledData ret = new RealLabelledData();

        for (ObservationReal aux: this)
        {
            double[] d = new double[aux.getAttributeSize()];

            for (int i = 0; i < d.length; i++)
                for (int j = 0; j < d.length; j++)
                {
                    d[i] += aux.getAttribute(j)*tmatrix[i][j];
                }
            ret.addObservation(new ObservationReal(aux.getLabel(),d));
        }

        return ret;
    }