Example #1
0
def add_tableau(request, loc_code):
    """ Respond to the "/add_tableau/XYZ" URL.

        We let the user add a new tableau to the given location.
    """
    if not request.user.is_authenticated:
        return HttpResponseRedirect(reverse(settings.ADMIN_HOME_VIEW))

    try:
        location = Location.objects.get(code=loc_code)
    except Location.DoesNotExist:
        return HttpResponseRedirect(reverse("location_editor.views.main"))

    if request.method == "GET":

        # We're displaying this form for the first time -> set up our default
        # values.

        name    = ""
        err_msg = None

    elif request.method == "POST":

        # The user is submitting this form.  See what the user wants to do.

        if request.POST.get("cancel") != None:
            # The user clicked on the "Cancel" button -> redirect the user back
            # to the main tableau page for this location.
            return HttpResponseRedirect(
                        reverse("tableau_editor.views.select",
                                args=[location.code]))

        # If we get here, the user is attempting to add a new tableau.  Check
        # that the entered name is valid.

        name    = request.POST.get("name")
        err_msg = None # initially.

        if Tableau.objects.filter(location=location, name=name).exists():
            err_msg = "Sorry, there is already a tableau with that name " \
                    + "for this location."

        if err_msg == None:
            # The entered name is valid -> add the tableau.
            tableau = Tableau()
            tableau.location  = location
            tableau.name      = name
            tableau.meta_data = "{}"
            tableau.save()

            # Return the user back to the main list of tableaux for this
            # location.

            return HttpResponseRedirect(
                        reverse("tableau_editor.views.select",
                                args=[location.code]))

    # Finally, display our page.

    menu_html = menus.generate(request, "Tableau Editor",
                               "tableau_editor", "add_tableau")

    return render_to_response("tableau_editor/templates/add_tableau.html",
                              {'menu_html' : menu_html,
                               'heading'   : "Add Tableau for "+str(location),
                               'name'      : name,
                               'err_msg'   : err_msg,
                              },
                              context_instance=RequestContext(request))
Example #2
0
def create_tableau(factory, location):
    """ Create a single tableau for a given location using a given factory.

        This function does the actual work of generating an individual tableau
        based upon the factory definition.  It can be called directly to
        generate a desired tableau, or it can be called indirectly by the
        daemon (using the private 'create_tableau' API call) to generate
        tableaux en masse.

        Upon completion, we return None if the tableau-generation attempt was
        successful.  Otherwise, we return a suitable error message explaining
        why the tableau could not be generated.
    """
    # Get the location's outline.

    try:
        outline = Outline.objects.get(location=location)
    except Outline.DoesNotExist:
        # We can't create a tableau for a location without an outline ->
        # tell the user the bad news.
        return "Location has no outline."

    # Delete the existing tableau with this name, if any.

    Tableau.objects.filter(location=location,
                           name=factory.tableau_name).delete()

    # Create the new Tableau for this location.

    tableau = Tableau()
    tableau.location      = location
    tableau.name          = factory.tableau_name
    tableau.meta_data     = factory.tableau_meta_data
    tableau.bounds_render = factory.tableau_bounds_render
    tableau.save()

    # Create a single view for the tableau, covering the location's entire
    # extent.

    min_long,min_lat,max_long,max_lat = outline.outline.extent

    # Add a margin around the edges so that the location is easier to see.

    width = abs(max_long - min_long)
    height = abs(max_lat - min_lat)

    buffer = 0.02 * (width + height) / 2

    min_long = min_long - buffer
    max_long = max_long + buffer
    min_lat  = min_lat  - buffer
    max_lat  = max_lat  + buffer

    # Ensure the calculated view bounds are allowable.

    if min_lat < MIN_ALLOWED_LATITUDE:
        min_lat = MIN_ALLOWED_LATITUDE
    elif min_lat > MAX_ALLOWED_LATITUDE:
        min_lat = MAX_ALLOWED_LATITUDE

    if max_lat < MIN_ALLOWED_LATITUDE:
        max_lat = MIN_ALLOWED_LATITUDE
    elif max_lat > MAX_ALLOWED_LATITUDE:
        max_lat = MAX_ALLOWED_LATITUDE

    if min_long < MIN_ALLOWED_LONGITUDE:
        min_long = MIN_ALLOWED_LONGITUDE
    elif min_long > MAX_ALLOWED_LONGITUDE:
        min_long = MAX_ALLOWED_LONGITUDE

    if max_long < MIN_ALLOWED_LONGITUDE:
        max_long = MIN_ALLOWED_LONGITUDE
    elif max_long > MAX_ALLOWED_LONGITUDE:
        max_long = MAX_ALLOWED_LONGITUDE

    # Create the view.

    view = TableauView()
    view.tableau       = tableau
    view.ordinal_rank  = 1
    view.name          = location.display_name
    view.min_lat       = "%0.4f" % min_lat
    view.max_lat       = "%0.4f" % max_lat
    view.min_long      = "%0.4f" % min_long
    view.max_long      = "%0.4f" % max_long
    view.meta_data     = factory.view_meta_data
    view.bounds_render = factory.view_bounds_render
    view.save()

    # Add the factory's filter(s) to the tableau's view.

    for factory_filter in factory.tableaufactoryviewfilter_set.all():
        filter = TableauViewFilter()
        filter.tableauView    = view
        filter.type           = factory_filter.filter_type
        filter.value          = factory_filter.filter_value
        filter.meta_data      = factory_filter.filter_meta_data
        filter.draw_bubbles   = factory_filter.filter_draw_bubbles
        filter.polygon_render = factory_filter.filter_polygon_render
        filter.bubble_render  = factory_filter.filter_bubble_render
        filter.save()

    # Calculate the aspect ratio for the tableau's view.

    proj = GlobalMercator()

    min_x,min_y = proj.LatLonToMeters(min_lat, min_long)
    max_x,max_y = proj.LatLonToMeters(max_lat, max_long)

    viewWidth  = max_x - min_x
    viewHeight = max_y - min_y

    if viewWidth == 0: viewWidth = 1.0
    if viewHeight == 0: viewHeight = 1.0

    aspectRatio = viewWidth / viewHeight

    # Create a single layout for the tableau.  The size of the layout is
    # based on the view's aspect ratio.

    layout_width = LAYOUT_MAX_WIDTH
    layout_height = layout_width / aspectRatio

    if layout_height > LAYOUT_MAX_HEIGHT:
        layout_height = LAYOUT_MAX_HEIGHT
        layout_width  = layout_height * aspectRatio

    layout = TableauLayout()
    layout.tableau = tableau
    layout.width   = layout_width
    layout.height  = layout_height
    layout.save()

    # Create a single TableauLayoutViewPosition record, positioning the view
    # within the layout.

    position = TableauLayoutViewPosition()
    position.tableauLayout = layout
    position.tableauView   = view
    position.min_x         = 0
    position.min_y         = 0
    position.max_x         = layout_width
    position.max_y         = layout_height
    position.save()

    # Finally, tell the caller that the tableau was successfully generated.

    return None