Base::Vector3d Extrusion::calculateShapeNormal(const App::PropertyLink& shapeLink)
{
    if (!shapeLink.getValue())
        throw Base::Exception("calculateShapeNormal: link is empty");
    const App::DocumentObject* docobj = shapeLink.getValue();

    //special case for sketches and the like: no matter what shape they have, use their local Z axis.
    if (docobj->isDerivedFrom(Part::Part2DObject::getClassTypeId())){
        const Part::Part2DObject* p2do = static_cast<const Part::Part2DObject*>(docobj);
        Base::Vector3d OZ (0.0, 0.0, 1.0);
        Base::Vector3d result;
        p2do->Placement.getValue().getRotation().multVec(OZ, result);
        return result;
    }

    //extract the shape
    if (! docobj->isDerivedFrom(Part::Feature::getClassTypeId()))
        throw Base::TypeError("Linked object doesn't have shape.");

    const TopoShape &tsh = static_cast<const Part::Feature*>(docobj)->Shape.getShape();
    TopoDS_Shape sh = tsh.getShape();
    if (sh.IsNull())
        throw Base::Exception("calculateShapeNormal: link points to a valid object, but its shape is null.");

    //find plane
    BRepLib_FindSurface planeFinder(sh, -1, /*OnlyPlane=*/true);
    if (! planeFinder.Found())
        throw Base::ValueError("Can't find normal direction, because the shape is not on a plane.");

    //find plane normal and return result.
    GeomAdaptor_Surface surf(planeFinder.Surface());
    gp_Dir normal = surf.Plane().Axis().Direction();

    //now se know the plane. But if there are faces, the
    //plane normal direction is not dependent on face orientation (because findPlane only uses edges).
    //let's fix that.
    TopExp_Explorer ex(sh, TopAbs_FACE);
    if(ex.More()) {
        BRepAdaptor_Surface surf(TopoDS::Face(ex.Current()));
        normal = surf.Plane().Axis().Direction();
        if (ex.Current().Orientation() == TopAbs_REVERSED){
            normal.Reverse();
        }
    }

    return Base::Vector3d(normal.X(), normal.Y(), normal.Z());
}
//DVA is still Source PropertyLink so needs different logic vs DV::Restore
void DrawViewArch::Restore(Base::XMLReader &reader)
{
// this is temporary code for backwards compat (within v0.17).  can probably be deleted once there are no development
// fcstd files with old property types in use. 
    reader.readElement("Properties");
    int Cnt = reader.getAttributeAsInteger("Count");

    for (int i=0 ;i<Cnt ;i++) {
        reader.readElement("Property");
        const char* PropName = reader.getAttribute("name");
        const char* TypeName = reader.getAttribute("type");
        App::Property* schemaProp = getPropertyByName(PropName);
        try {
            if(schemaProp){
                if (strcmp(schemaProp->getTypeId().getName(), TypeName) == 0){        //if the property type in obj == type in schema
                    schemaProp->Restore(reader);                                      //nothing special to do
                } else if (strcmp(PropName, "Source") == 0) {
                    App::PropertyLinkGlobal glink;
                    App::PropertyLink link;
                    if (strcmp(glink.getTypeId().getName(),TypeName) == 0) {            //property in file is plg
                        glink.setContainer(this);
                        glink.Restore(reader);
                        if (glink.getValue() != nullptr) {
                            static_cast<App::PropertyLink*>(schemaProp)->setScope(App::LinkScope::Global);
                            static_cast<App::PropertyLink*>(schemaProp)->setValue(glink.getValue());
                        }
                    } else if (strcmp(link.getTypeId().getName(),TypeName) == 0) {            //property in file is pl
                        link.setContainer(this);
                        link.Restore(reader);
                        if (link.getValue() != nullptr) {
                            static_cast<App::PropertyLink*>(schemaProp)->setScope(App::LinkScope::Global);
                            static_cast<App::PropertyLink*>(schemaProp)->setValue(link.getValue());
                        }
                    
                    } else {
                        // has Source prop isn't PropertyLink or PropertyLinkGlobal! 
                        Base::Console().Log("DrawViewArch::Restore - old Document Source is weird: %s\n", TypeName);
                        // no idea
                    }
                } else {
                    Base::Console().Log("DrawViewArch::Restore - old Document has unknown Property\n");
                }
            }
        }
        catch (const Base::XMLParseException&) {
            throw; // re-throw
        }
        catch (const Base::Exception &e) {
            Base::Console().Error("%s\n", e.what());
        }
        catch (const std::exception &e) {
            Base::Console().Error("%s\n", e.what());
        }
        catch (const char* e) {
            Base::Console().Error("%s\n", e);
        }
#ifndef FC_DEBUG
        catch (...) {
            Base::Console().Error("PropertyContainer::Restore: Unknown C++ exception thrown\n");
        }
#endif

        reader.readEndElement("Property");
    }
    reader.readEndElement("Properties");

}